1 /*
2 * Copyright (c) 2021-2024 HPMicro
3 *
4 * SPDX-License-Identifier: BSD-3-Clause
5 *
6 * Change Logs:
7 * Date Author Notes
8 * 2024-02-20 HPMicro First version
9 */
10
11 #include <rtthread.h>
12
13 #ifdef BSP_USING_RTT_LCD_DRIVER
14 #include "board.h"
15 #include "hpm_l1c_drv.h"
16 #include "hpm_lcdc_drv.h"
17 #include "hpm_pdma_drv.h"
18 #include "hpm_panel.h"
19
20
21 #define LCD_BITS_PER_PIXEL 16
22 #define LCD_PIXEL_FORMAT RTGRAPHIC_PIXEL_FORMAT_RGB565
23 #define LCD_LAYER_INDEX (0)
24 #define LCD_LAYER_DONE_MASK (1U << LCD_LAYER_INDEX)
25 struct hpm_lcd
26 {
27 LCDC_Type *lcd_base;
28 rt_uint8_t lcd_irq;
29 struct rt_semaphore lcd_lock;
30 char *bus_name;
31 struct rt_device parent;
32 struct rt_device_graphic_info lcd_info;
33 uint32_t lcd_buffer_size;
34 };
35
36 static rt_err_t hpm_lcd_init(struct rt_device *device);
37 static rt_err_t hpm_lcd_control(struct rt_device *device, int cmd, void *args);
38 static int hpm_lcdc_init(struct hpm_lcd *lcd, struct rt_device_graphic_info *info);
39
40 static uint8_t __attribute__((section(".framebuffer"), aligned(HPM_L1C_CACHELINE_SIZE))) lcdc_framebuffer[PANEL_SIZE_WIDTH * PANEL_SIZE_HEIGHT * LCD_BITS_PER_PIXEL / 8];
41
42
43 #ifdef RT_USING_DEVICE_OPS
44 const struct rt_device_ops hpm_lcd_ops = {
45 .init = hpm_lcd_init,
46 .open = RT_NULL,
47 .close = RT_NULL,
48 .read = RT_NULL,
49 .write = RT_NULL,
50 .control = hpm_lcd_control,
51 };
52 #endif
53
54 static struct hpm_lcd hpm_lcds[] =
55 {
56 {
57 .bus_name = "lcd0",
58 .lcd_buffer_size = (PANEL_SIZE_WIDTH * PANEL_SIZE_HEIGHT * LCD_BITS_PER_PIXEL / 8),
59 .lcd_base = HPM_LCDC,
60 .lcd_irq = BOARD_LCD_IRQ,
61 .parent.type = RT_Device_Class_Graphic,
62 #ifdef RT_USING_DEVICE_OPS
63 .parent.ops = &hpm_lcd_ops,
64 #else
65 .parent.init = hpm_lcd_init,
66 .parent.open = RT_NULL,
67 .parent.close = RT_NULL,
68 .parent.read = RT_NULL,
69 .parent.write = RT_NULL,
70 .parent.control = hpm_lcd_control,
71 #endif
72 },
73 };
74
isr_lcd_d0(void)75 void isr_lcd_d0(void)
76 {
77 lcdc_disable_interrupt(hpm_lcds[0].lcd_base, LCDC_INT_EN_VSYNC_MASK);
78 rt_sem_release(&hpm_lcds[0].lcd_lock);
79 lcdc_clear_status(hpm_lcds[0].lcd_base, LCDC_ST_VSYNC_MASK);
80 }
SDK_DECLARE_EXT_ISR_M(BOARD_LCD_IRQ,isr_lcd_d0)81 SDK_DECLARE_EXT_ISR_M(BOARD_LCD_IRQ, isr_lcd_d0)
82
83 static rt_err_t hpm_lcd_init(struct rt_device *device)
84 {
85 /* nothing, right now */
86 (void *)device;
87 return RT_EOK;
88 }
89
hpm_lcd_control(struct rt_device * device,int cmd,void * args)90 static rt_err_t hpm_lcd_control(struct rt_device *device, int cmd, void *args)
91 {
92 uint32_t aligned_start, aligned_end, aligned_size;
93 struct hpm_lcd *lcd = (struct hpm_lcd *)device->user_data;
94 hpm_panel_t *panel = hpm_panel_find_device_default();
95 struct rt_device_graphic_info *info = RT_NULL;
96 uint32_t buffer;
97
98 switch (cmd)
99 {
100 case RTGRAPHIC_CTRL_SET_MODE:
101 info = (struct rt_device_graphic_info *)args;
102 rt_sem_trytake(&lcd->lcd_lock);
103 lcdc_disable_interrupt(lcd->lcd_base, LCDC_INT_EN_VSYNC_MASK);
104 rt_thread_delay(10);
105 hpm_lcdc_init(lcd, info);
106 break;
107
108 case RTGRAPHIC_CTRL_RECT_UPDATE:
109 if (args != RT_NULL)
110 {
111 buffer = (uint32_t)args;
112 }
113 else
114 {
115 buffer = (uint32_t)lcd->lcd_info.framebuffer;
116 }
117 if (l1c_dc_is_enabled())
118 {
119 aligned_start = HPM_L1C_CACHELINE_ALIGN_DOWN(buffer);
120 aligned_end = HPM_L1C_CACHELINE_ALIGN_UP(buffer + lcd->lcd_buffer_size);
121 aligned_size = aligned_end - aligned_start;
122 l1c_dc_writeback(aligned_start, aligned_size);
123 }
124 if (lcdc_layer_control_shadow_loaded(lcd->lcd_base, 0))
125 {
126 lcdc_layer_set_next_buffer(lcd->lcd_base, 0, (rt_uint32_t)buffer);
127 }
128 break;
129
130 case RTGRAPHIC_CTRL_WAIT_VSYNC:
131 rt_sem_trytake(&lcd->lcd_lock);
132 lcdc_enable_interrupt(lcd->lcd_base, LCDC_INT_EN_VSYNC_MASK);
133 rt_sem_take(&lcd->lcd_lock, RT_WAITING_FOREVER);
134 break;
135
136 case RTGRAPHIC_CTRL_POWERON:
137 hpm_panel_set_backlight(panel, true);
138 break;
139
140 case RTGRAPHIC_CTRL_POWEROFF:
141 hpm_panel_set_backlight(panel, false);
142 break;
143
144 case RTGRAPHIC_CTRL_GET_INFO:
145 info = (struct rt_device_graphic_info *)args;
146
147 RT_ASSERT(info != RT_NULL);
148 info->pixel_format = lcd->lcd_info.pixel_format;
149 info->bits_per_pixel = 16;
150 info->width = lcd->lcd_info.width;
151 info->height = lcd->lcd_info.height;
152 info->framebuffer = lcd->lcd_info.framebuffer;
153 break;
154
155 default:
156 break;
157 }
158 }
159
hpm_lcdc_init(struct hpm_lcd * lcd,struct rt_device_graphic_info * info)160 static int hpm_lcdc_init(struct hpm_lcd *lcd, struct rt_device_graphic_info *info)
161 {
162 lcdc_config_t config = {0};
163 display_pixel_format_t pixel_format;
164 lcdc_get_default_config(lcd->lcd_base, &config);
165 board_panel_para_to_lcdc(&config);
166
167 if (info->framebuffer == RT_NULL)
168 {
169 return -RT_ERROR;
170 }
171 rt_memcpy(&lcd->lcd_info, info, sizeof(struct rt_device_graphic_info));
172 lcd->lcd_info.framebuffer = lcdc_framebuffer;
173 if (info->pixel_format == RTGRAPHIC_PIXEL_FORMAT_RGB565)
174 {
175 pixel_format = display_pixel_format_rgb565;
176 }
177 else if (info->pixel_format == RTGRAPHIC_PIXEL_FORMAT_ARGB888)
178 {
179 pixel_format = display_pixel_format_rgb565;
180 }
181 else {
182 return -RT_ERROR;
183 }
184 lcdc_init(lcd->lcd_base, &config);
185 memset(lcd->lcd_info.framebuffer, 0, info->width * info->height * info->bits_per_pixel / 8);
186 lcdc_layer_config_t layer;
187 lcdc_get_default_layer_config(lcd->lcd_base, &layer, pixel_format, LCD_LAYER_INDEX);
188
189 layer.position_x = 0;
190 layer.position_y = 0;
191 layer.width = info->width;
192 layer.height = info->height;
193 layer.buffer = (rt_uint32_t)lcd->lcd_info.framebuffer;
194 layer.background.u = 0;
195
196 if (status_success != lcdc_config_layer(lcd->lcd_base, LCD_LAYER_INDEX, &layer, true)) {
197 return -RT_ERROR;
198 }
199
200 lcdc_turn_on_display(lcd->lcd_base);
201 lcdc_enable_interrupt(lcd->lcd_base, LCDC_INT_EN_VSYNC_MASK);
202 intc_m_enable_irq_with_priority(lcd->lcd_irq, 7);
203 return 0;
204 }
205
drv_lcd_hw_init(void)206 int drv_lcd_hw_init(void)
207 {
208 rt_err_t result = RT_EOK;
209 struct rt_device_graphic_info lcd_info;
210 for (uint32_t i = 0; i < sizeof(hpm_lcds) / sizeof(hpm_lcds[0]); i++)
211 {
212 struct hpm_lcd *lcd = &hpm_lcds[i];
213 struct rt_device *device = &lcd->parent;
214 lcd->parent.user_data = lcd;
215 /* init lcd_lock semaphore */
216 result = rt_sem_init(&hpm_lcds[0].lcd_lock, "lcd_lock", 0, RT_IPC_FLAG_FIFO);
217 if (result != RT_EOK)
218 {
219 result = -RT_ENOMEM;
220 goto __exit;
221 }
222 /* config LCD dev info */
223
224 lcd_info.height = PANEL_SIZE_HEIGHT;
225 lcd_info.width = PANEL_SIZE_WIDTH;
226 lcd_info.bits_per_pixel = LCD_BITS_PER_PIXEL;
227 lcd_info.pixel_format = LCD_PIXEL_FORMAT;
228 lcd_info.framebuffer = lcdc_framebuffer;
229 /* register lcd device */
230 rt_device_register(device, hpm_lcds[i].bus_name, RT_DEVICE_FLAG_RDWR);
231 board_init_lcd();
232 if (hpm_lcdc_init(&hpm_lcds[i], &lcd_info) != RT_EOK)
233 {
234 result = -RT_ERROR;
235 goto __exit;
236 }
237 __exit:
238 if (result != RT_EOK)
239 {
240 rt_sem_delete(&hpm_lcds[i].lcd_lock);
241 }
242 return result;
243 }
244 }
245 INIT_BOARD_EXPORT(drv_lcd_hw_init);
246
247 #endif /* BSP_USING_RTT_LCD_DRIVER */
248