summaryrefslogtreecommitdiffstats
path: root/plat/nuvoton/npcm845x/npcm845x_serial_port.c
blob: 946e9d076e387399dc20f5f77db5299662b699e9 (plain)
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
/*
 * Copyright (c) 2015-2023, ARM Limited and Contributors. All rights reserved.
 *
 * Copyright (C) 2017-2023 Nuvoton Ltd.
 *
 * SPDX-License-Identifier: BSD-3-Clause
 */

#include <stdbool.h>

#include <arch.h>
#include <arch_helpers.h>
#include <common/debug.h>
#include <drivers/arm/gicv2.h>
#include <drivers/delay_timer.h>
#include <drivers/generic_delay_timer.h>
#include <lib/mmio.h>
#include <lib/psci/psci.h>
#include <npcm845x_clock.h>
#include <npcm845x_gcr.h>
#include <npcm845x_lpuart.h>
#include <plat_npcm845x.h>


uintptr_t npcm845x_get_base_uart(UART_DEV_T devNum)
{
	return 0xF0000000 + devNum * 0x1000;
}

uintptr_t npcm845x_get_base_clk(void)
{
	return 0xF0801000;
}

uintptr_t npcm845x_get_base_gcr(void)
{
	return 0xF0800000;
}

void npcm845x_wait_for_empty(int uart_n)
{
	volatile struct npcmX50_uart *uart = (struct npcmX50_uart *)npcm845x_get_base_uart(uart_n);

	while ((*(uint8_t *)(uintptr_t)(&uart->lsr) & 0x40) == 0x00) {
/*
 * wait for THRE (Transmitter Holding Register Empty)
 * and TSR (Transmitter Shift Register) to be empty.
 * Some delay. notice needed some delay so UartUpdateTool
 * will pass w/o error log
 */
	}

	volatile int delay;

	for (delay = 0; delay < 10000; delay++) {
		;
	}
}

int UART_Init(UART_DEV_T devNum,  UART_BAUDRATE_T baudRate)
{
	uint32_t val = 0;
	uintptr_t clk_base = npcm845x_get_base_clk();
	uintptr_t gcr_base =  npcm845x_get_base_gcr();
	uintptr_t uart_base = npcm845x_get_base_uart(devNum);
	volatile struct npcmX50_uart *uart = (struct npcmX50_uart *)uart_base;

/* Use  CLKREF to be independent of CPU frequency */
	volatile struct clk_ctl *clk_ctl_obj = (struct clk_ctl *)clk_base;
	volatile struct npcm845x_gcr *gcr_ctl_obj =
		(struct npcm845x_gcr *)gcr_base;

	clk_ctl_obj->clksel = clk_ctl_obj->clksel & ~(0x3 << 8);
	clk_ctl_obj->clksel = clk_ctl_obj->clksel | (0x2 << 8);

	/* Set devider according to baudrate */
	clk_ctl_obj->clkdiv1 =
		(unsigned int)(clk_ctl_obj->clkdiv1 & ~(0x1F << 16));

	/* clear bits 11-15 - set value 0 */
	if (devNum == UART3_DEV) {
		clk_ctl_obj->clkdiv2 =
			(unsigned int)(clk_ctl_obj->clkdiv2 & ~(0x1F << 11));
	}

	npcm845x_wait_for_empty(devNum);

	val = (uint32_t)LCR_WLS_8bit;
	mmio_write_8((uintptr_t)&uart->lcr, (uint8_t)val);

	/* disable all interrupts */
	mmio_write_8((uintptr_t)&uart->ier, 0);

	/*
	 * Set the RX FIFO trigger level, reset RX, TX FIFO
	 */
	val = (uint32_t)(FCR_FME | FCR_RFR | FCR_TFR | FCR_RFITL_4B);

	/* reset TX and RX FIFO */
	mmio_write_8((uintptr_t)(&uart->fcr), (uint8_t)val);

	/* Set port for 8 bit, 1 stop, no parity */
	val = (uint32_t)LCR_WLS_8bit;

	/* Set DLAB bit; Accesses the Divisor Latch Registers (DLL, DLM). */
	val |= 0x80;
	mmio_write_8((uintptr_t)(&uart->lcr), (uint8_t)val);

	/* Baud Rate = UART Clock 24MHz / (16 * (11+2)) = 115384 */
	mmio_write_8((uintptr_t)(&uart->dll), 11);
	mmio_write_8((uintptr_t)(&uart->dlm), 0x00);

	val = mmio_read_8((uintptr_t)&uart->lcr);

	/* Clear DLAB bit; Accesses RBR, THR or IER registers. */
	val &= 0x7F;
	mmio_write_8((uintptr_t)(&uart->lcr), (uint8_t)val);

	if (devNum == UART0_DEV) {
		gcr_ctl_obj->mfsel4 &= ~(1 << 1);
		gcr_ctl_obj->mfsel1 |= 1 << 9;
	} else if (devNum == UART3_DEV) {
		/* Pin Mux */
		gcr_ctl_obj->mfsel4 &= ~(1 << 1);
		gcr_ctl_obj->mfsel1 |= 1 << 11;
		gcr_ctl_obj->spswc &= (7 << 0);
		gcr_ctl_obj->spswc |= (2 << 0);
	} else {
		/* halt */
		while (1) {
			;
		}
	}

	return 0;
}