// Copyright lowRISC contributors.
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
// SPDX-License-Identifier: Apache-2.0

#include "sw/device/lib/base/mmio.h"
#include "sw/device/lib/dif/dif_rv_plic.h"
#include "sw/device/lib/dif/dif_uart.h"
#include "sw/device/lib/runtime/hart.h"
#include "sw/device/lib/runtime/irq.h"
#include "sw/device/lib/runtime/log.h"
#include "sw/device/lib/testing/test_framework/check.h"
#include "sw/device/lib/testing/test_framework/ottf_main.h"
#include "sw/device/lib/testing/test_framework/status.h"

#include "hw/top_earlgrey/sw/autogen/top_earlgrey.h"

static const uint32_t kPlicTarget = kTopEarlgreyPlicTargetIbex0;

static dif_rv_plic_t plic0;
static dif_uart_t uart0;

// These flags are used in the test routine to verify that a corresponding
// interrupt has elapsed, and has been serviced. These are declared as volatile
// since they are referenced in the ISR routine as well as in the main program
// flow.
static volatile bool uart_rx_overflow_handled;
static volatile bool uart_tx_empty_handled;

/**
 * UART ISR.
 *
 * Services UART interrupts, sets the appropriate flags that are used to
 * determine success or failure of the test.
 */
static void handle_uart_isr(const dif_rv_plic_irq_id_t interrupt_id) {
  // NOTE: This initialization is superfluous, since the `default` case below
  // is effectively noreturn, but the compiler is unable to prove this.
  dif_uart_irq_t uart_irq = 0;

  switch (interrupt_id) {
    case kTopEarlgreyPlicIrqIdUart0RxOverflow:
      CHECK(!uart_rx_overflow_handled,
            "UART RX overflow IRQ asserted more than once");

      uart_irq = kDifUartIrqRxOverflow;
      uart_rx_overflow_handled = true;
      break;
    case kTopEarlgreyPlicIrqIdUart0TxEmpty:
      CHECK(!uart_tx_empty_handled,
            "UART TX empty IRQ asserted more than once");

      uart_irq = kDifUartIrqTxEmpty;
      uart_tx_empty_handled = true;
      break;
    default:
      LOG_FATAL("ISR is not implemented!");
      test_status_set(kTestStatusFailed);
  }

  CHECK_DIF_OK(dif_uart_irq_acknowledge(&uart0, uart_irq));
}

/**
 * External ISR.
 *
 * Handles all peripheral interrupts on Ibex. PLIC asserts an external interrupt
 * line to the CPU, which results in a call to this OTTF ISR. This ISR
 * overrides the default OTTF implementation.
 */
void ottf_external_isr(void) {
  // Claim the IRQ by reading the Ibex specific CC register.
  dif_rv_plic_irq_id_t interrupt_id;
  CHECK_DIF_OK(dif_rv_plic_irq_claim(&plic0, kPlicTarget, &interrupt_id));

  // Check if the interrupted peripheral is UART.
  top_earlgrey_plic_peripheral_t peripheral_id =
      top_earlgrey_plic_interrupt_for_peripheral[interrupt_id];
  CHECK(peripheral_id == kTopEarlgreyPlicPeripheralUart0,
        "ISR interrupted peripheral is not UART!");
  handle_uart_isr(interrupt_id);

  // Complete the IRQ by writing the IRQ source to the Ibex specific CC
  // register.
  CHECK_DIF_OK(dif_rv_plic_irq_complete(&plic0, kPlicTarget, interrupt_id));
}

static void uart_initialise(mmio_region_t base_addr, dif_uart_t *uart) {
  CHECK_DIF_OK(dif_uart_init(base_addr, uart));
  CHECK_DIF_OK(
      dif_uart_configure(uart, (dif_uart_config_t){
                                   .baudrate = kUartBaudrate,
                                   .clk_freq_hz = kClockFreqPeripheralHz,
                                   .parity_enable = kDifToggleDisabled,
                                   .parity = kDifUartParityEven,
                                   .tx_enable = kDifToggleEnabled,
                                   .rx_enable = kDifToggleEnabled,
                               }));
}

/**
 * Configures all the relevant interrupts in UART.
 */
static void uart_configure_irqs(dif_uart_t *uart) {
  CHECK_DIF_OK(dif_uart_irq_set_enabled(&uart0, kDifUartIrqRxOverflow,
                                        kDifToggleEnabled));
  CHECK_DIF_OK(
      dif_uart_irq_set_enabled(&uart0, kDifUartIrqTxEmpty, kDifToggleEnabled));
}

/**
 * Configures all the relevant interrupts in PLIC.
 */
static void plic_configure_irqs(dif_rv_plic_t *plic) {
  // Set IRQ priorities to MAX
  CHECK_DIF_OK(dif_rv_plic_irq_set_priority(
      plic, kTopEarlgreyPlicIrqIdUart0RxOverflow, kDifRvPlicMaxPriority));

  CHECK_DIF_OK(dif_rv_plic_irq_set_priority(
      plic, kTopEarlgreyPlicIrqIdUart0TxEmpty, kDifRvPlicMaxPriority));

  // Set Ibex IRQ priority threshold level
  CHECK_DIF_OK(dif_rv_plic_target_set_threshold(&plic0, kPlicTarget,
                                                kDifRvPlicMinPriority));

  // Enable IRQs in PLIC
  CHECK_DIF_OK(dif_rv_plic_irq_set_enabled(plic,
                                           kTopEarlgreyPlicIrqIdUart0RxOverflow,
                                           kPlicTarget, kDifToggleEnabled));

  CHECK_DIF_OK(dif_rv_plic_irq_set_enabled(
      plic, kTopEarlgreyPlicIrqIdUart0TxEmpty, kPlicTarget, kDifToggleEnabled));
}

static void execute_test(dif_uart_t *uart) {
  // Force UART RX overflow interrupt.
  uart_rx_overflow_handled = false;
  CHECK_DIF_OK(dif_uart_irq_force(uart, kDifUartIrqRxOverflow, true));
  // Check if the IRQ has occured and has been handled appropriately.
  if (!uart_rx_overflow_handled) {
    busy_spin_micros(10);
  }
  CHECK(uart_rx_overflow_handled, "RX overflow IRQ has not been handled!");

  // Force UART TX empty interrupt.
  uart_tx_empty_handled = false;
  CHECK_DIF_OK(dif_uart_irq_force(uart, kDifUartIrqTxEmpty, true));
  // Check if the IRQ has occured and has been handled appropriately.
  if (!uart_tx_empty_handled) {
    busy_spin_micros(10);
  }
  CHECK(uart_tx_empty_handled, "TX empty IRQ has not been handled!");
}

OTTF_DEFINE_TEST_CONFIG(.enable_concurrency = false,
                        .can_clobber_uart = true, );

bool test_main(void) {
  // Enable IRQs on Ibex
  irq_global_ctrl(true);
  irq_external_ctrl(true);

  // No debug output in case of UART initialisation failure.
  mmio_region_t uart_base_addr =
      mmio_region_from_addr(TOP_EARLGREY_UART0_BASE_ADDR);
  uart_initialise(uart_base_addr, &uart0);

  mmio_region_t plic_base_addr =
      mmio_region_from_addr(TOP_EARLGREY_RV_PLIC_BASE_ADDR);
  CHECK_DIF_OK(dif_rv_plic_init(plic_base_addr, &plic0));

  uart_configure_irqs(&uart0);
  plic_configure_irqs(&plic0);
  execute_test(&uart0);

  return true;
}
