1 /*
2  * SPDX-FileCopyrightText: 2021 Espressif Systems (Shanghai) CO LTD
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #include "freertos/FreeRTOS.h"
8 #include "soc/soc_caps.h"
9 #include "esp_lcd_common.h"
10 #if SOC_LCDCAM_SUPPORTED
11 #include "hal/lcd_ll.h"
12 #include "hal/lcd_hal.h"
13 
14 typedef struct esp_lcd_platform_t {
15     portMUX_TYPE spinlock; // spinlock used to protect platform level resources
16     union {
17         void *panels[SOC_LCD_RGB_PANELS]; // array of RGB LCD panel instances
18         void *buses[SOC_LCD_I80_BUSES];   // array of i80 bus instances
19     }; // LCD peripheral can only work under either RGB mode or intel 8080 mode
20 } esp_lcd_platform_t;
21 
22 esp_lcd_platform_t s_lcd_platform = {
23     .spinlock = (portMUX_TYPE)portMUX_INITIALIZER_UNLOCKED,
24     .buses = {} // initially the bus slots and panel slots are empty
25 };
26 
lcd_com_register_device(lcd_com_device_type_t device_type,void * device_obj)27 int lcd_com_register_device(lcd_com_device_type_t device_type, void *device_obj)
28 {
29     int member_id = -1;
30     switch (device_type) {
31     case LCD_COM_DEVICE_TYPE_I80:
32         // search for a bus slot then register to platform
33         for (int i = 0; (i < SOC_LCD_I80_BUSES) && (member_id == -1); i++) {
34             portENTER_CRITICAL(&s_lcd_platform.spinlock);
35             if (!s_lcd_platform.buses[i]) {
36                 s_lcd_platform.buses[i] = device_obj;
37                 member_id = i;
38             }
39             portEXIT_CRITICAL(&s_lcd_platform.spinlock);
40         }
41         break;
42     case LCD_COM_DEVICE_TYPE_RGB:
43         // search for a panel slot then register to platform
44         for (int i = 0; (i < SOC_LCD_RGB_PANELS) && (member_id == -1); i++) {
45             portENTER_CRITICAL(&s_lcd_platform.spinlock);
46             if (!s_lcd_platform.panels[i]) {
47                 s_lcd_platform.panels[i] = device_obj;
48                 member_id = i;
49             }
50             portEXIT_CRITICAL(&s_lcd_platform.spinlock);
51         }
52         break;
53     default:
54         break;
55     }
56     return member_id;
57 }
58 
lcd_com_remove_device(lcd_com_device_type_t device_type,int member_id)59 void lcd_com_remove_device(lcd_com_device_type_t device_type, int member_id)
60 {
61     switch (device_type) {
62     case LCD_COM_DEVICE_TYPE_I80:
63         portENTER_CRITICAL(&s_lcd_platform.spinlock);
64         if (s_lcd_platform.buses[member_id]) {
65             s_lcd_platform.buses[member_id] = NULL;
66         }
67         portEXIT_CRITICAL(&s_lcd_platform.spinlock);
68         break;
69     case LCD_COM_DEVICE_TYPE_RGB:
70         portENTER_CRITICAL(&s_lcd_platform.spinlock);
71         if (s_lcd_platform.panels[member_id]) {
72             s_lcd_platform.panels[member_id] = NULL;
73         }
74         portEXIT_CRITICAL(&s_lcd_platform.spinlock);
75         break;
76     default:
77         break;
78     }
79 }
80 #endif // SOC_LCDCAM_SUPPORTED
81 
lcd_com_mount_dma_data(dma_descriptor_t * desc_head,const void * buffer,size_t len)82 void lcd_com_mount_dma_data(dma_descriptor_t *desc_head, const void *buffer, size_t len)
83 {
84     size_t prepared_length = 0;
85     uint8_t *data = (uint8_t *)buffer;
86     dma_descriptor_t *desc = desc_head;
87     while (len > DMA_DESCRIPTOR_BUFFER_MAX_SIZE) {
88         desc->dw0.suc_eof = 0; // not the end of the transaction
89         desc->dw0.size = DMA_DESCRIPTOR_BUFFER_MAX_SIZE;
90         desc->dw0.length = DMA_DESCRIPTOR_BUFFER_MAX_SIZE;
91         desc->dw0.owner = DMA_DESCRIPTOR_BUFFER_OWNER_DMA;
92         desc->buffer = &data[prepared_length];
93         desc = desc->next; // move to next descriptor
94         prepared_length += DMA_DESCRIPTOR_BUFFER_MAX_SIZE;
95         len -= DMA_DESCRIPTOR_BUFFER_MAX_SIZE;
96     }
97     if (len) {
98         desc->dw0.suc_eof = 1; // end of the transaction
99         desc->dw0.size = len;
100         desc->dw0.length = len;
101         desc->dw0.owner = DMA_DESCRIPTOR_BUFFER_OWNER_DMA;
102         desc->buffer = &data[prepared_length];
103         desc = desc->next; // move to next descriptor
104         prepared_length += len;
105     }
106 }
107