early_console.c 3.1 KB
Newer Older
1
// SPDX-License-Identifier: GPL-2.0-only
2 3 4 5 6 7
/*
 * Joshua Henderson <joshua.henderson@microchip.com>
 * Copyright (C) 2015 Microchip Technology Inc.  All rights reserved.
 */
#include <asm/mach-pic32/pic32.h>
#include <asm/fw/fw.h>
8
#include <asm/setup.h>
9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29

#include "pic32mzda.h"
#include "early_pin.h"

/* Default early console parameters */
#define EARLY_CONSOLE_PORT	1
#define EARLY_CONSOLE_BAUDRATE	115200

#define UART_ENABLE		BIT(15)
#define UART_ENABLE_RX		BIT(12)
#define UART_ENABLE_TX		BIT(10)
#define UART_TX_FULL		BIT(9)

/* UART1(x == 0) - UART6(x == 5) */
#define UART_BASE(x)	((x) * 0x0200)
#define U_MODE(x)	UART_BASE(x)
#define U_STA(x)	(UART_BASE(x) + 0x10)
#define U_TXR(x)	(UART_BASE(x) + 0x20)
#define U_BRG(x)	(UART_BASE(x) + 0x40)

static void __iomem *uart_base;
30
static int console_port = -1;
31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49

static int __init configure_uart_pins(int port)
{
	switch (port) {
	case 1:
		pic32_pps_input(IN_FUNC_U2RX, IN_RPB0);
		pic32_pps_output(OUT_FUNC_U2TX, OUT_RPG9);
		break;
	case 5:
		pic32_pps_input(IN_FUNC_U6RX, IN_RPD0);
		pic32_pps_output(OUT_FUNC_U6TX, OUT_RPB8);
		break;
	default:
		return -1;
	}

	return 0;
}

50
static void __init configure_uart(int port, int baud)
51 52 53 54 55 56 57 58 59 60 61 62
{
	u32 pbclk;

	pbclk = pic32_get_pbclk(2);

	__raw_writel(0, uart_base + U_MODE(port));
	__raw_writel(((pbclk / baud) / 16) - 1, uart_base + U_BRG(port));
	__raw_writel(UART_ENABLE, uart_base + U_MODE(port));
	__raw_writel(UART_ENABLE_TX | UART_ENABLE_RX,
		     uart_base + PIC32_SET(U_STA(port)));
}

63
static void __init setup_early_console(int port, int baud)
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
{
	if (configure_uart_pins(port))
		return;

	console_port = port;
	configure_uart(console_port, baud);
}

static char * __init pic32_getcmdline(void)
{
	/*
	 * arch_mem_init() has not been called yet, so we don't have a real
	 * command line setup if using CONFIG_CMDLINE_BOOL.
	 */
#ifdef CONFIG_CMDLINE_OVERRIDE
	return CONFIG_CMDLINE;
#else
	return fw_getcmdline();
#endif
}

static int __init get_port_from_cmdline(char *arch_cmdline)
{
	char *s;
	int port = -1;

	if (!arch_cmdline || *arch_cmdline == '\0')
		goto _out;

	s = strstr(arch_cmdline, "earlyprintk=");
	if (s) {
		s = strstr(s, "ttyS");
		if (s)
			s += 4;
		else
			goto _out;

		port = (*s) - '0';
	}

_out:
	return port;
}

static int __init get_baud_from_cmdline(char *arch_cmdline)
{
	char *s;
	int baud = -1;

	if (!arch_cmdline || *arch_cmdline == '\0')
		goto _out;

	s = strstr(arch_cmdline, "earlyprintk=");
	if (s) {
		s = strstr(s, "ttyS");
		if (s)
			s += 6;
		else
			goto _out;

		baud = 0;
		while (*s >= '0' && *s <= '9')
			baud = baud * 10 + *s++ - '0';
	}

_out:
	return baud;
}

133
void __init fw_init_early_console(void)
134 135
{
	char *arch_cmdline = pic32_getcmdline();
136
	int baud, port;
137

138
	uart_base = ioremap(PIC32_BASE_UART, 0xc00);
139 140

	baud = get_baud_from_cmdline(arch_cmdline);
141
	port = get_port_from_cmdline(arch_cmdline);
142 143 144 145 146 147 148 149 150 151

	if (port == -1)
		port = EARLY_CONSOLE_PORT;

	if (baud == -1)
		baud = EARLY_CONSOLE_BAUDRATE;

	setup_early_console(port, baud);
}

152
void prom_putchar(char c)
153 154 155 156 157 158 159 160 161
{
	if (console_port >= 0) {
		while (__raw_readl(
				uart_base + U_STA(console_port)) & UART_TX_FULL)
			;

		__raw_writel(c, uart_base + U_TXR(console_port));
	}
}