blob: c43a1d024d7374104414b0601866d453b68650ee [file] [log] [blame]
David Brazdil3d7b88b2019-07-22 17:19:35 +01001/*
2 * Copyright 2019 The Hafnium Authors.
3 *
Andrew Walbran23417d82020-06-17 14:44:22 +01004 * Use of this source code is governed by a BSD-style
5 * license that can be found in the LICENSE file or at
6 * https://opensource.org/licenses/BSD-3-Clause.
David Brazdil3d7b88b2019-07-22 17:19:35 +01007 */
8
9#include "hf/io.h"
10#include "hf/mm.h"
11#include "hf/mpool.h"
12#include "hf/plat/console.h"
13
14/* clang-format off */
15
16#define GPFSEL1 IO32_C(GPIO_BASE + 0x4)
17
18#define AUX_ENABLES IO32_C(AUX_BASE + 0x4)
19#define AUX_MU_IO_REG IO32_C(AUX_BASE + 0x40)
20#define AUX_MU_IER_REG IO32_C(AUX_BASE + 0x44)
21#define AUX_MU_LCR_REG IO32_C(AUX_BASE + 0x4c)
22#define AUX_MU_MCR_REG IO32_C(AUX_BASE + 0x50)
23#define AUX_MU_LSR_REG IO32_C(AUX_BASE + 0x54)
24#define AUX_MU_CNTL_REG IO32_C(AUX_BASE + 0x60)
25#define AUX_MU_BAUD_REG IO32_C(AUX_BASE + 0x68)
26
27#define AUX_MU_LSR_TX_EMPTY (UINT32_C(1) << 5)
28#define AUX_MU_LSR_TX_IDLE (UINT32_C(1) << 6)
29
30#define MHZ_TO_HZ UINT32_C(1000000)
31
32/* clang-format on */
33
34void plat_console_init(void)
35{
36 uint32_t selector;
37
38 selector = io_read32(GPFSEL1);
39 /* Set GPIO14 to function 5. */
40 selector &= ~(7 << 12);
41 selector |= 2 << 12;
42 /* Set GPIO15 to function 5 */
43 selector &= ~(7 << 15);
44 selector |= 2 << 15;
45 io_write32(GPFSEL1, selector);
46
47 /*
48 * With 8-times oversampling, baudrate is calculated as:
49 * baudrate = system_clock_freq / (8 * (baudrate_reg + 1))
50 * Therefore:
51 * baudrate_reg = (system_clock_freq / (8 * baudrate)) -1
52 */
53 uint32_t system_clock_freq = UINT32_C(CORE_FREQ_MHZ) * MHZ_TO_HZ;
54 uint32_t oversampled_baudrate = UINT32_C(8) * UINT32_C(BAUDRATE);
55 uint32_t baudrate_reg =
56 (system_clock_freq / oversampled_baudrate) - UINT32_C(1);
57
58 /* Enable Mini UART and access to its registers. */
59 io_write32(AUX_ENABLES, 1);
60 /* Disable auto flow control and disable receiver and transmitter. */
61 io_write32(AUX_MU_CNTL_REG, 0);
62 /* Disable receive and transmit interrupts. */
63 io_write32(AUX_MU_IER_REG, 0);
64 /* Enable 8 bit mode. */
65 io_write32(AUX_MU_LCR_REG, 3);
66 /* Set RTS line to be always high. */
67 io_write32(AUX_MU_MCR_REG, 0);
68 /* Set baud rate. */
69 io_write32(AUX_MU_BAUD_REG, baudrate_reg);
70 /* Enable transmitter and receiver. */
71 io_write32(AUX_MU_CNTL_REG, 3);
72
73 memory_ordering_barrier();
74}
75
76void plat_console_mm_init(struct mm_stage1_locked stage1_locked,
77 struct mpool *ppool)
78{
79 mm_identity_map(stage1_locked, pa_init(GPIO_BASE),
80 pa_add(pa_init(GPIO_BASE), PAGE_SIZE),
81 MM_MODE_R | MM_MODE_W | MM_MODE_D, ppool);
82 mm_identity_map(stage1_locked, pa_init(AUX_BASE),
83 pa_add(pa_init(AUX_BASE), PAGE_SIZE),
84 MM_MODE_R | MM_MODE_W | MM_MODE_D, ppool);
85}
86
87void plat_console_putchar(char c)
88{
89 /* Print a carriage-return as well. */
90 if (c == '\n') {
91 plat_console_putchar('\r');
92 }
93
94 /* Wait for the transmitter to be ready to accept a byte. */
95 while ((io_read32(AUX_MU_LSR_REG) & AUX_MU_LSR_TX_EMPTY) == 0) {
96 }
97
98 /* Write data to transmitter FIFO. */
99 memory_ordering_barrier();
100 io_write32(AUX_MU_IO_REG, c);
101 memory_ordering_barrier();
102
103 /* Wait until the transmitter is no longer busy. */
104 while ((io_read32(AUX_MU_LSR_REG) & AUX_MU_LSR_TX_IDLE) == 0) {
105 }
106}
David Brazdilb38816f2020-01-31 16:31:10 +0000107
108char plat_console_getchar(void)
109{
110 /* Wait for the transmitter to be ready to deliver a byte. */
111 while (!(io_read32(AUX_MU_LSR_REG) & 0x1)) {
112 }
113
114 /* Read data from transmitter FIFO. */
115 return (char)(io_read32(AUX_MU_IO_REG) & 0xff);
116}