/* * Copyright (c) 2021-2024 HPMicro * * SPDX-License-Identifier: BSD-3-Clause * * Change Logs: * Date Author Notes * 2024-02-20 HPMicro First version */ #include #ifdef BSP_USING_RTT_LCD_DRIVER #include "board.h" #include "hpm_l1c_drv.h" #include "hpm_lcdc_drv.h" #include "hpm_pdma_drv.h" #include "hpm_panel.h" #define LCD_BITS_PER_PIXEL 16 #define LCD_PIXEL_FORMAT RTGRAPHIC_PIXEL_FORMAT_RGB565 #define LCD_LAYER_INDEX (0) #define LCD_LAYER_DONE_MASK (1U<lcd_base, LCDC_INT_EN_VSYNC_MASK); rt_sem_release(&hpm_lcds_pram->lcd_lock); lcdc_clear_status(hpm_lcds_pram->lcd_base, LCDC_ST_VSYNC_MASK); } #endif /* HPM_USING_RTTHREAD_INTERRUPT_FRAMEWORK */ static rt_err_t hpm_lcd_init(struct rt_device *device) { /* nothing, right now */ (void *)device; return RT_EOK; } static rt_err_t hpm_lcd_control(struct rt_device *device, int cmd, void *args) { uint32_t aligned_start, aligned_end, aligned_size; struct hpm_lcd *lcd = (struct hpm_lcd *)device->user_data; hpm_panel_t *panel = hpm_panel_find_device_default(); struct rt_device_graphic_info *info = RT_NULL; uint32_t buffer; rt_err_t err = RT_EOK; switch (cmd) { case RTGRAPHIC_CTRL_SET_MODE: info = (struct rt_device_graphic_info *)args; rt_sem_trytake(&lcd->lcd_lock); lcdc_disable_interrupt(lcd->lcd_base, LCDC_INT_EN_VSYNC_MASK); rt_thread_delay(10); err = hpm_lcdc_init(lcd, info); break; case RTGRAPHIC_CTRL_RECT_UPDATE: if (args != RT_NULL) { buffer = (uint32_t)args; } else { buffer = (uint32_t)lcd->lcd_info.framebuffer; } if (l1c_dc_is_enabled()) { aligned_start = HPM_L1C_CACHELINE_ALIGN_DOWN(buffer); aligned_end = HPM_L1C_CACHELINE_ALIGN_UP(buffer + lcd->lcd_buffer_size); aligned_size = aligned_end - aligned_start; l1c_dc_writeback(aligned_start, aligned_size); } if (lcdc_layer_control_shadow_loaded(lcd->lcd_base, 0)) { lcdc_layer_set_next_buffer(lcd->lcd_base, 0, (rt_uint32_t)buffer); } break; case RTGRAPHIC_CTRL_WAIT_VSYNC: rt_sem_trytake(&lcd->lcd_lock); lcdc_enable_interrupt(lcd->lcd_base, LCDC_INT_EN_VSYNC_MASK); rt_sem_take(&lcd->lcd_lock, RT_WAITING_FOREVER); break; case RTGRAPHIC_CTRL_POWERON: hpm_panel_set_backlight(panel, true); break; case RTGRAPHIC_CTRL_POWEROFF: hpm_panel_set_backlight(panel, false); break; case RTGRAPHIC_CTRL_GET_INFO: info = (struct rt_device_graphic_info *)args; RT_ASSERT(info != RT_NULL); info->pixel_format = lcd->lcd_info.pixel_format; info->bits_per_pixel = 16; info->width = lcd->lcd_info.width; info->height = lcd->lcd_info.height; info->framebuffer = lcd->lcd_info.framebuffer; break; default: break; } return err; } static int hpm_lcdc_init(struct hpm_lcd *lcd, struct rt_device_graphic_info *info) { lcdc_config_t config = {0}; display_pixel_format_t pixel_format; lcdc_get_default_config(lcd->lcd_base, &config); board_panel_para_to_lcdc(&config); if (info->framebuffer == RT_NULL) { return -RT_ERROR; } rt_memcpy(&lcd->lcd_info, info, sizeof(struct rt_device_graphic_info)); lcd->lcd_info.framebuffer = lcdc_framebuffer; if (info->pixel_format == RTGRAPHIC_PIXEL_FORMAT_RGB565) { pixel_format = display_pixel_format_rgb565; } else if (info->pixel_format == RTGRAPHIC_PIXEL_FORMAT_ARGB888) { pixel_format = display_pixel_format_rgb565; } else { return -RT_ERROR; } lcdc_init(lcd->lcd_base, &config); memset(lcd->lcd_info.framebuffer, 0, info->width * info->height * info->bits_per_pixel / 8); lcdc_layer_config_t layer; lcdc_get_default_layer_config(lcd->lcd_base, &layer, pixel_format, LCD_LAYER_INDEX); layer.position_x = 0; layer.position_y = 0; layer.width = info->width; layer.height = info->height; layer.buffer = (rt_uint32_t)lcd->lcd_info.framebuffer; layer.background.u = 0; if (status_success != lcdc_config_layer(lcd->lcd_base, LCD_LAYER_INDEX, &layer, true)) { return -RT_ERROR; } lcdc_turn_on_display(lcd->lcd_base); lcdc_enable_interrupt(lcd->lcd_base, LCDC_INT_EN_VSYNC_MASK); intc_m_enable_irq_with_priority(lcd->lcd_irq, lcd->lcd_irq_priority); return 0; } int drv_lcd_hw_init(void) { rt_err_t result = RT_EOK; struct rt_device_graphic_info lcd_info; for (uint32_t i = 0; i < sizeof(hpm_lcds) / sizeof(hpm_lcds[0]); i++) { struct hpm_lcd *lcd = &hpm_lcds[i]; struct rt_device *device = &lcd->parent; lcd->parent.user_data = lcd; /* init lcd_lock semaphore */ result = rt_sem_init(&hpm_lcds[0].lcd_lock, "lcd_lock", 0, RT_IPC_FLAG_FIFO); if (result != RT_EOK) { result = -RT_ENOMEM; goto __exit; } /* config LCD dev info */ lcd_info.height = PANEL_SIZE_HEIGHT; lcd_info.width = PANEL_SIZE_WIDTH; lcd_info.bits_per_pixel = LCD_BITS_PER_PIXEL; lcd_info.pixel_format = LCD_PIXEL_FORMAT; lcd_info.framebuffer = lcdc_framebuffer; /* register lcd device */ rt_device_register(device, hpm_lcds[i].bus_name, RT_DEVICE_FLAG_RDWR); board_init_lcd(); if (hpm_lcdc_init(&hpm_lcds[i], &lcd_info) != RT_EOK) { result = -RT_ERROR; goto __exit; } #ifdef HPM_USING_RTTHREAD_INTERRUPT_FRAMEWORK /* Register LCD device to irq table */ rt_hw_interrupt_install(hpm_lcds[i].lcd_irq, (rt_isr_handler_t)isr_lcd_d, hpm_lcds[i], hpm_lcds[i].bus_name); #endif /* HPM_USING_RTTHREAD_INTERRUPT_FRAMEWORK */ __exit: if (result != RT_EOK) { rt_sem_delete(&hpm_lcds[i].lcd_lock); } return result; } } INIT_BOARD_EXPORT(drv_lcd_hw_init); #endif /* BSP_USING_RTT_LCD_DRIVER */