1/**
2 * \file plat_apm88xxxx.c
3 * \brief
4 */
5
6/*
7 * Copyright (c) 2016 ETH Zurich.
8 * All rights reserved.
9 *
10 * This file is distributed under the terms in the attached LICENSE file.
11 * If you do not find this file, copies can be found by writing to:
12 * ETH Zurich D-INFK, Universitaetsstrasse 6, CH-8092 Zurich. Attn: Systems Group.
13 */
14
15#include <kernel.h>
16#include <offsets.h>
17#include <arch/arm/platform.h>
18#include <serial.h>
19#include <dev/apm88xxxx/apm88xxxx_pc16550_dev.h>
20#include <arch/arm/gic.h>
21#include <sysreg.h>
22#include <dev/armv8_dev.h>
23#include <barrelfish_kpi/arm_core_data.h>
24#include <psci.h>
25#include <arch/armv8/global.h>
26#include <paging_kernel_arch.h>
27
28/* the maximum number of UARTS supported */
29#define MAX_NUM_UARTS 4
30
31static apm88xxxx_pc16550_t ports[MAX_NUM_UARTS];
32
33
34errval_t serial_init(unsigned port, bool initialize_hw)
35{
36    if (port >= MAX_NUM_UARTS) {
37        return SYS_ERR_SERIAL_PORT_INVALID;
38    }
39
40    if ((lpaddr_t)ports[port].base == (platform_uart_base[port] + KERNEL_OFFSET)) {
41        return SYS_ERR_OK;
42    }
43
44    apm88xxxx_pc16550_t *uart = &ports[port];
45    apm88xxxx_pc16550_initialize(uart, (mackerel_addr_t)(platform_uart_base[port] + KERNEL_OFFSET));
46
47    if (!initialize_hw) {
48        // hw initialized, this is for non-bsp cores, where hw has been
49        // initialized by bsp core and we come through here just to setup our
50        // local apm88xxxx_pc16550 struct for the port.
51        return SYS_ERR_OK;
52    }
53
54    panic("device init NYI");
55    return SYS_ERR_OK;
56}
57
58errval_t serial_early_init(unsigned port)
59{
60    if (port >= MAX_NUM_UARTS) {
61        return SYS_ERR_SERIAL_PORT_INVALID;
62    }
63
64    if ((lpaddr_t)ports[port].base == platform_uart_base[port]) {
65        return SYS_ERR_OK;
66    }
67
68    apm88xxxx_pc16550_t *uart = &ports[port];
69    apm88xxxx_pc16550_initialize(uart, (mackerel_addr_t)platform_uart_base[port]);
70    return SYS_ERR_OK;
71}
72
73errval_t serial_early_init_mmu_enabled(unsigned port)
74{
75    return serial_early_init(port);
76}
77
78
79/**
80 * \brief Prints a single character to a serial port.
81 */
82void serial_putchar(unsigned port, char c)
83{
84    assert(port < MAX_NUM_UARTS);
85    assert(ports[port].base != 0);
86    // Wait until FIFO can hold more characters
87    while(!apm88xxxx_pc16550_LSR_thre_rdf(&ports[port]));
88    // Write character
89    apm88xxxx_pc16550_THR_thr_wrf(&ports[port], c);
90}
91
92/**
93 * \brief Reads a single character from the default serial port.
94 * This function spins waiting for a character to arrive.
95 */
96char serial_getchar(unsigned port)
97{
98    assert(port < MAX_NUM_UARTS);
99    assert(ports[port].base != 0);
100
101    // Wait until character available
102    while(!apm88xxxx_pc16550_LSR_dr_rdf(&ports[port]));
103    // Read a character from FIFO
104    return apm88xxxx_pc16550_RBR_rbr_rdf(&ports[port]);
105}
106
107
108void platform_get_info(struct platform_info *pi)
109{
110    pi->arch = PI_ARCH_ARMV8A;
111    pi->platform = PI_PLATFORM_APM88XXXX;
112}
113
114void armv8_get_info(struct arch_info_armv8 *ai)
115{
116
117}
118
119void platform_revision_init(void)
120{
121
122}
123
124errval_t platform_boot_core(hwid_t target, genpaddr_t gen_entry, genpaddr_t context)
125{
126    printf("Invoking PSCI on: cpu=0x%lx, entry=0x%lx, context=0x%lx\n", target, gen_entry, context);
127    struct armv8_core_data *cd = (struct armv8_core_data *)local_phys_to_mem(context);
128    cd->page_table_root = armv8_TTBR1_EL1_rd(NULL);
129    cd->cpu_driver_globals_pointer = (uintptr_t)global;
130    __asm volatile("dsb   sy\n"
131                   "dmb   sy\n"
132                   "isb     \n");
133
134    /*
135     * An IRQ interrupt, even if the PSTATE I-bit is set.
136An FIQ interrupt, even if the PSTATE F-bit is set.
137     *
138     *
139     */
140
141    gic_raise_softirq(target, 1);
142
143    return SYS_ERR_OK;
144}
145
146/*
147 * Return the core count
148 */
149size_t platform_get_core_count(void)
150{
151    return 0;
152}
153
154uint32_t platform_get_timer_interrupt(void){
155    // TODO (LH): Untested
156    return 30;
157}
158