blob: 899133ad5a2d33f0535489ebcd7773e55b4bf427 [file] [log] [blame]
/*
* Copyright 2023 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "hw/top_matcha/sw/autogen/top_matcha.h"
#include "sw/device/lib/arch/device.h"
#include "sw/device/lib/camera_hm01b0.h"
#include "sw/device/lib/dif/dif_cam_ctrl.h"
#include "sw/device/lib/dif/dif_isp_wrapper.h"
#include "sw/device/lib/dif/dif_rv_plic.h"
#include "sw/device/lib/dif/dif_spi_host.h"
#include "sw/device/lib/dif/dif_tlul_mailbox.h"
#include "sw/device/lib/dif/dif_uart.h"
#include "sw/device/lib/runtime/irq.h"
#include "sw/device/lib/runtime/print.h"
#include "sw/device/lib/spi_display/LCD_Driver.h"
#include "sw/device/lib/spi_display/spi_display.h"
#include "sw/device/lib/testing/test_framework/check.h"
#include "sw/device/lib/testing/test_framework/ottf_test_config.h"
#include "sw/device/lib/testing/test_framework/test_util.h"
OTTF_DEFINE_TEST_CONFIG();
static spi_display_t spi_display;
static dif_cam_ctrl_t cam_ctrl;
static dif_uart_t smc_uart;
static dif_spi_host_t spi_host2;
static dif_isp_wrapper_t isp_wrapper;
static dif_tlul_mailbox_t tlul_mailbox;
static dif_rv_plic_t plic_smc;
// 320x240 RGB565 buffer, contains the pixel data
// to be drawn to the display.
static uint16_t rgb565_buffer[LCD_WIDTH * LCD_HEIGHT];
static PAINT paint_ctx;
static volatile bool isp_frame_done_irq_seen = false;
void ottf_external_isr(void) {
dif_rv_plic_irq_id_t plic_irq_id;
// Clear IRQ from the tlul_mailbox and claim it from the PLIC.
CHECK_DIF_OK(dif_rv_plic_irq_claim(&plic_smc, kTopMatchaPlicTargetIbex0Smc,
&plic_irq_id));
top_matcha_plic_peripheral_smc_t peripheral_id =
top_matcha_plic_interrupt_for_peripheral_smc[plic_irq_id];
switch (peripheral_id) {
case kTopMatchaPlicPeripheralCamI2c: {
CHECK_DIF_OK(camera_hm01b0_irq_handler(plic_irq_id));
break;
}
case kTopMatchaPlicPeripheralIspWrapper: {
uint32_t mi_mis, isp_mis;
CHECK_DIF_OK(dif_isp_wrapper_read_mi_mis(&isp_wrapper, &mi_mis));
CHECK_DIF_OK(dif_isp_wrapper_read_isp_mis(&isp_wrapper, &isp_mis));
CHECK_DIF_OK(dif_isp_wrapper_write_isp_icr(&isp_wrapper, isp_mis));
CHECK_DIF_OK(dif_isp_wrapper_write_mi_icr(&isp_wrapper, mi_mis));
CHECK_DIF_OK(dif_isp_wrapper_irq_acknowledge_all(&isp_wrapper));
if (isp_mis & (1 << 5)) {
isp_frame_done_irq_seen = true;
}
break;
}
case kTopMatchaPlicPeripheralTlulMailboxSmc: {
CHECK_DIF_OK(spi_display_smc_mailbox_irq_handler(&spi_display));
break;
}
case kTopMatchaPlicPeripheralSpiHost2: {
CHECK_DIF_OK(spi_display_spi_irq_handler(&spi_display));
break;
}
default:
LOG_FATAL("Unexpected peripheral_id!");
}
CHECK_DIF_OK(dif_rv_plic_irq_complete(&plic_smc, kTopMatchaPlicTargetIbex0Smc,
plic_irq_id));
}
void _ottf_main(void) {
// Config_Init
init_uart(TOP_MATCHA_SMC_UART_BASE_ADDR, &smc_uart);
LOG_INFO("spi_display_smc");
// Initialize cam_ctrl and ISP.
CHECK_DIF_OK(dif_cam_ctrl_init(
mmio_region_from_addr(TOP_MATCHA_CAM_CTRL_BASE_ADDR), &cam_ctrl));
CHECK_DIF_OK(dif_isp_wrapper_init(
mmio_region_from_addr(TOP_MATCHA_ISP_WRAPPER_BASE_ADDR), &isp_wrapper));
// Configure Mailbox.
CHECK_DIF_OK(dif_tlul_mailbox_init(
mmio_region_from_addr(TOP_MATCHA_TLUL_MAILBOX_SMC_BASE_ADDR),
&tlul_mailbox));
CHECK_DIF_OK(dif_tlul_mailbox_irq_set_enabled(
&tlul_mailbox, kDifTlulMailboxIrqRtirq, kDifToggleEnabled));
CHECK_DIF_OK(dif_tlul_mailbox_irq_set_enabled(
&tlul_mailbox, kDifTlulMailboxIrqWtirq, kDifToggleEnabled));
CHECK_DIF_OK(dif_tlul_mailbox_irq_set_enabled(
&tlul_mailbox, kDifTlulMailboxIrqEirq, kDifToggleEnabled));
CHECK_DIF_OK(dif_rv_plic_init(
mmio_region_from_addr(TOP_MATCHA_RV_PLIC_SMC_BASE_ADDR), &plic_smc));
// Configure interrupts for Camera, ISP and mailbox.
CHECK_DIF_OK(camera_hm01b0_irq_init(&plic_smc, kTopMatchaPlicTargetIbex0Smc));
CHECK_DIF_OK(dif_rv_plic_irq_set_enabled(
&plic_smc, kTopMatchaPlicIrqIdIspWrapperIsp, kTopMatchaPlicTargetIbex0Smc,
kDifToggleEnabled));
CHECK_DIF_OK(dif_rv_plic_irq_set_enabled(
&plic_smc, kTopMatchaPlicIrqIdIspWrapperMi, kTopMatchaPlicTargetIbex0Smc,
kDifToggleEnabled));
CHECK_DIF_OK(dif_rv_plic_irq_set_priority(
&plic_smc, kTopMatchaPlicIrqIdIspWrapperIsp, kDifRvPlicMaxPriority));
CHECK_DIF_OK(dif_rv_plic_irq_set_priority(
&plic_smc, kTopMatchaPlicIrqIdIspWrapperMi, kDifRvPlicMaxPriority));
CHECK_DIF_OK(dif_rv_plic_irq_set_enabled(
&plic_smc, kTopMatchaPlicIrqIdTlulMailboxSmcRtirq,
kTopMatchaPlicTargetIbex0Smc, kDifToggleEnabled));
CHECK_DIF_OK(dif_rv_plic_irq_set_priority(
&plic_smc, kTopMatchaPlicIrqIdTlulMailboxSmcRtirq, 1));
irq_global_ctrl(true);
irq_external_ctrl(true);
// Initialize the SPI host and display.
CHECK_DIF_OK(dif_spi_host_init(
mmio_region_from_addr(TOP_MATCHA_SPI_HOST2_BASE_ADDR), &spi_host2));
dif_spi_host_config_t config = {
.spi_clock = kClockFreqSpiDisplayHz,
.peripheral_clock_freq_hz = kClockFreqCpuHz,
};
CHECK_DIF_OK(dif_spi_host_configure(&spi_host2, config));
CHECK_DIF_OK(dif_spi_host_output_set_enabled(&spi_host2, /*enabled=*/true));
CHECK_DIF_OK(spi_display_init(&spi_display, &spi_host2, &tlul_mailbox));
CHECK_DIF_OK(spi_display_irq_init(&spi_display, &plic_smc,
kTopMatchaPlicIrqIdSpiHost2SpiEvent,
kTopMatchaPlicTargetIbex0Smc));
// Configure and enable camera.
CHECK_DIF_OK(camera_hm01b0_init());
CHECK_DIF_OK(camera_hm01b0_set_default_registers(
kCameraHm01b0Resolution320x240, kCameraHm01b0FrameRate1Fps));
CHECK_DIF_OK(dif_isp_wrapper_set_raw_320x240_byp_320x240_en(&isp_wrapper));
CHECK_DIF_OK(dif_cam_ctrl_set_en(&cam_ctrl));
Paint_NewImage(&paint_ctx, LCD_WIDTH, LCD_HEIGHT, ROTATE_0, MIRROR_NONE);
while (true) {
while (!isp_frame_done_irq_seen) {
asm volatile("wfi");
}
isp_frame_done_irq_seen = false;
for (int i = 0; i < LCD_WIDTH * LCD_HEIGHT; ++i) {
uint8_t y = *(((const uint8_t*)TOP_MATCHA_ML_TOP_DMEM_BASE_ADDR) + i);
uint16_t rgb565 =
((y >> 3) & 0x1F) << 11 | ((y >> 2) & 0x3F) << 5 | ((y >> 3) & 0x1F);
rgb565_buffer[i] = __builtin_bswap16(rgb565);
}
memset(paint_ctx.Image, 0xF0, sizeof(paint_ctx.Image));
// This is an placeholder string, to demonstrate drawing
// something like the output scores from a model.
Paint_DrawString_EN(&paint_ctx, 0, 0, "(-127, -127)", &Font16, BLACK,
WHITE);
for (int i = 0; i < LCD_WIDTH * LCD_HEIGHT; ++i) {
if (paint_ctx.Image[i] == 0xF0F0) {
continue;
}
rgb565_buffer[i] = __builtin_bswap16(paint_ctx.Image[i]);
}
LCD_ClearToBuffer(&spi_display, rgb565_buffer);
}
while (true) {
asm volatile("wfi");
}
}