Reworked DMA driver, it's working now with OK performance regarding screen refresh rate. Need to clean source files up now
This commit is contained in:
parent
0353e42482
commit
9c46eff761
@ -8,16 +8,18 @@
|
|||||||
|
|
||||||
#include "lv_port_indev.h"
|
#include "lv_port_indev.h"
|
||||||
|
|
||||||
static lv_color_t lvgl_draw_buffer[LCD_PIXEL_WIDTH * LCD_PIXEL_HEIGHT / 10];
|
#define LVGL_GFX_BUFFER_SIZE (LCD_PIXEL_WIDTH * LCD_PIXEL_HEIGHT / 2)
|
||||||
|
|
||||||
|
static lv_color_t lvgl_draw_buffer[LVGL_GFX_BUFFER_SIZE];
|
||||||
static lv_disp_draw_buf_t lvgl_draw_buffer_dsc;
|
static lv_disp_draw_buf_t lvgl_draw_buffer_dsc;
|
||||||
|
|
||||||
static lv_disp_drv_t display_driver;
|
lv_disp_drv_t display_driver;
|
||||||
static LCDConfig_t LCDConfig;
|
static LCDConfig_t LCDConfig;
|
||||||
|
|
||||||
static void lvgl_display_flush_cb(lv_disp_drv_t *disp_drv, const lv_area_t *area, lv_color_t *color_p)
|
static void lvgl_display_flush_cb(lv_disp_drv_t *disp_drv, const lv_area_t *area, lv_color_t *color_p)
|
||||||
{
|
{
|
||||||
lcd_draw_rect_frame(&LCDConfig, area->x1, area->y1, area->x2 - area->x1 + 1, area->y2 - area->y1 + 1, (uint8_t *)color_p);
|
lcd_draw_rect_frame(&LCDConfig, area->x1, area->y1, area->x2 - area->x1 + 1, area->y2 - area->y1 + 1, (uint8_t *)color_p);
|
||||||
lv_disp_flush_ready(disp_drv);
|
//lv_disp_flush_ready(disp_drv);
|
||||||
}
|
}
|
||||||
|
|
||||||
struct tm temptm = {0};
|
struct tm temptm = {0};
|
||||||
@ -29,29 +31,22 @@ static void date_time_cb(struct tm * const dateTime)
|
|||||||
/*time_t time_type = time(NULL);
|
/*time_t time_type = time(NULL);
|
||||||
struct tm *tm = localtime(&time_type);*/
|
struct tm *tm = localtime(&time_type);*/
|
||||||
|
|
||||||
|
temptm.tm_min++;
|
||||||
|
temptm.tm_sec = 1;
|
||||||
|
|
||||||
|
if(temptm.tm_min == 60)
|
||||||
|
{
|
||||||
|
temptm.tm_min = 0;
|
||||||
|
temptm.tm_hour++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(temptm.tm_hour == 24)
|
||||||
|
temptm.tm_hour = 0;
|
||||||
|
|
||||||
|
*dateTime = temptm;
|
||||||
|
|
||||||
//LV_LOG_USER("Time is : %llu, Time : %d:%d:%d", time_type, tm->tm_hour, tm->tm_min, tm->tm_sec);
|
//LV_LOG_USER("Time is : %llu, Time : %d:%d:%d", time_type, tm->tm_hour, tm->tm_min, tm->tm_sec);
|
||||||
*dateTime = temptm;
|
LV_LOG_USER("Time : %d:%d:%d", dateTime->tm_hour, dateTime->tm_min, dateTime->tm_sec);
|
||||||
}
|
|
||||||
|
|
||||||
static void tick_timer_irq(u8 *arg)
|
|
||||||
{
|
|
||||||
lv_tick_inc(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
void lv_create_tick(void)
|
|
||||||
{
|
|
||||||
u8 timer_id;
|
|
||||||
struct tls_timer_cfg timer_cfg;
|
|
||||||
|
|
||||||
timer_cfg.unit = TLS_TIMER_UNIT_MS;
|
|
||||||
timer_cfg.timeout = 1;
|
|
||||||
timer_cfg.is_repeat = 1;
|
|
||||||
timer_cfg.callback = (tls_timer_irq_callback)tick_timer_irq;
|
|
||||||
timer_cfg.arg = NULL;
|
|
||||||
timer_id = tls_timer_create(&timer_cfg);
|
|
||||||
tls_timer_start(timer_id);
|
|
||||||
// printf("timer start\n");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
WatchFace_t watchFace;
|
WatchFace_t watchFace;
|
||||||
@ -59,12 +54,10 @@ MenuScreen_t menuScreen;
|
|||||||
|
|
||||||
void gfx_task(void *param)
|
void gfx_task(void *param)
|
||||||
{
|
{
|
||||||
TickType_t time_ref = tls_os_get_time();
|
|
||||||
APP_LOG_TRACE("starting");
|
APP_LOG_TRACE("starting");
|
||||||
|
|
||||||
/* Initialize the lvgl library*/
|
/* Initialize the lvgl library*/
|
||||||
lv_init();
|
lv_init();
|
||||||
lv_create_tick();
|
|
||||||
|
|
||||||
/* Create, initialize and register the display driver*/
|
/* Create, initialize and register the display driver*/
|
||||||
lv_disp_drv_init(&display_driver);
|
lv_disp_drv_init(&display_driver);
|
||||||
@ -74,7 +67,7 @@ void gfx_task(void *param)
|
|||||||
|
|
||||||
display_driver.rotated = LV_DISP_ROT_180;
|
display_driver.rotated = LV_DISP_ROT_180;
|
||||||
|
|
||||||
lv_disp_draw_buf_init(&lvgl_draw_buffer_dsc, lvgl_draw_buffer, NULL, LCD_PIXEL_WIDTH * LCD_PIXEL_HEIGHT / 10);
|
lv_disp_draw_buf_init(&lvgl_draw_buffer_dsc, lvgl_draw_buffer, NULL, LVGL_GFX_BUFFER_SIZE);
|
||||||
|
|
||||||
display_driver.draw_buf = &lvgl_draw_buffer_dsc;
|
display_driver.draw_buf = &lvgl_draw_buffer_dsc;
|
||||||
display_driver.flush_cb = &(lvgl_display_flush_cb);
|
display_driver.flush_cb = &(lvgl_display_flush_cb);
|
||||||
@ -106,21 +99,24 @@ void gfx_task(void *param)
|
|||||||
|
|
||||||
lv_port_indev_init();
|
lv_port_indev_init();
|
||||||
|
|
||||||
watch_face_init(&watchFace);
|
/*watch_face_init(&watchFace);
|
||||||
menu_screen_init(&menuScreen);
|
menu_screen_init(&menuScreen);
|
||||||
|
|
||||||
watch_face_register_cb(&watchFace, &(date_time_cb));
|
watch_face_register_cb(&watchFace, &(date_time_cb));
|
||||||
watch_face_create(&watchFace);
|
watch_face_create(&watchFace);
|
||||||
|
|
||||||
lv_scr_load(watchFace.display);
|
lv_scr_load(watchFace.display);*/
|
||||||
|
//lv_demo_widgets();
|
||||||
|
//lv_demo_benchmark();
|
||||||
|
lv_demo_stress();
|
||||||
|
|
||||||
for(;;)
|
for(;;)
|
||||||
{
|
{
|
||||||
lv_timer_handler();
|
lv_timer_handler();
|
||||||
tls_os_time_delay_until(&time_ref, pdMS_TO_TICKS(5));
|
tls_os_time_delay(5);
|
||||||
|
|
||||||
static u32 counter = 0;
|
/* static u32 counter = 0;
|
||||||
if(counter++ % 200 == 0)
|
if(counter++ % 200 == 0)
|
||||||
APP_LOG_DEBUG("GFX ALIVE");
|
APP_LOG_DEBUG("GFX ALIVE");*/
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -4,8 +4,8 @@
|
|||||||
#include "wm_include.h"
|
#include "wm_include.h"
|
||||||
|
|
||||||
|
|
||||||
#define GFX_STACK_SIZE_IN_BYTES (4096 * sizeof(StackType_t))
|
#define GFX_STACK_SIZE_IN_BYTES (512 * sizeof(StackType_t))
|
||||||
#define GFX_STACK_PRIORITY (5)//(31)
|
#define GFX_STACK_PRIORITY (5)
|
||||||
|
|
||||||
static u8 gfx_task_stack[GFX_STACK_SIZE_IN_BYTES];
|
static u8 gfx_task_stack[GFX_STACK_SIZE_IN_BYTES];
|
||||||
tls_os_task_t gfx_task_handle;
|
tls_os_task_t gfx_task_handle;
|
||||||
|
@ -226,7 +226,7 @@ void lcd_set_window(LCDConfig_t * const LCDConfig, u16 x_start, u16 y_start, u16
|
|||||||
void lcd_draw_rect_frame(LCDConfig_t * const LCDConfig, u16 x, u16 y, u16 width, u16 height, u8 *data)
|
void lcd_draw_rect_frame(LCDConfig_t * const LCDConfig, u16 x, u16 y, u16 width, u16 height, u8 *data)
|
||||||
{
|
{
|
||||||
// First we check if the MMC peripheral is ready to write :
|
// First we check if the MMC peripheral is ready to write :
|
||||||
mmc_sdio_driver_wait_write_dma_ready();
|
//mmc_sdio_driver_wait_write_dma_ready();
|
||||||
|
|
||||||
// We tell the display where we want to draw the frame as well as it's size
|
// We tell the display where we want to draw the frame as well as it's size
|
||||||
lcd_set_window(LCDConfig, x, y, x + width - 1, y + height - 1);
|
lcd_set_window(LCDConfig, x, y, x + width - 1, y + height - 1);
|
||||||
@ -241,6 +241,20 @@ void lcd_draw_rect_frame(LCDConfig_t * const LCDConfig, u16 x, u16 y, u16 width,
|
|||||||
{
|
{
|
||||||
mmc_sdio_driver_write_one(data[i]);
|
mmc_sdio_driver_write_one(data[i]);
|
||||||
}*/
|
}*/
|
||||||
|
|
||||||
|
/*uint16_t size = width * height * 2, cursor = 0;
|
||||||
|
u16 writeLen = 0;
|
||||||
|
for(; size != 0; )
|
||||||
|
{
|
||||||
|
if(size > 512)
|
||||||
|
writeLen = 512;
|
||||||
|
else
|
||||||
|
writeLen = size;
|
||||||
|
|
||||||
|
mmc_sdio_driver_write(data + cursor, writeLen);
|
||||||
|
size -= writeLen;
|
||||||
|
cursor += writeLen;
|
||||||
|
}*/
|
||||||
}
|
}
|
||||||
|
|
||||||
void lcd_set_backlight(LCDConfig_t * const LCDConfig, u8 brightness)
|
void lcd_set_backlight(LCDConfig_t * const LCDConfig, u8 brightness)
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
#include "wm_include.h"
|
#include "wm_include.h"
|
||||||
#include "app_log.h"
|
#include "app_log.h"
|
||||||
#include "FreeRTOS.h"
|
#include "FreeRTOS.h"
|
||||||
|
#include "lvgl.h"
|
||||||
|
|
||||||
static u8 sdio_spi_dma_channel = 0xFF;
|
static u8 sdio_spi_dma_channel = 0xFF;
|
||||||
static u32 sdio_spi_dma_buf_size = 0;
|
static u32 sdio_spi_dma_buf_size = 0;
|
||||||
@ -30,7 +31,7 @@ void mmc_sdio_driver_periph_init(void)
|
|||||||
#if (0) // Clock frequency is 1/2 of system clock
|
#if (0) // Clock frequency is 1/2 of system clock
|
||||||
SDIO_HOST->MMC_CTL = 0x542 | 0 << 3; // auto transfer, mmc mode.
|
SDIO_HOST->MMC_CTL = 0x542 | 0 << 3; // auto transfer, mmc mode.
|
||||||
#else /* Clock frequency is 1/4 of system clock */
|
#else /* Clock frequency is 1/4 of system clock */
|
||||||
SDIO_HOST->MMC_CTL = 0x542 | (0b001 << 3); // 001
|
SDIO_HOST->MMC_CTL = 0x542 | (0b000 << 3); // 001
|
||||||
#endif
|
#endif
|
||||||
SDIO_HOST->MMC_INT_MASK = 0x100; //unmask sdio data interrupt.
|
SDIO_HOST->MMC_INT_MASK = 0x100; //unmask sdio data interrupt.
|
||||||
SDIO_HOST->MMC_CRCCTL = 0x00;
|
SDIO_HOST->MMC_CRCCTL = 0x00;
|
||||||
@ -73,24 +74,26 @@ static void mmc_sdio_driver_dma_callback(void *arg)
|
|||||||
else*/
|
else*/
|
||||||
{
|
{
|
||||||
tls_dma_free(sdio_spi_dma_channel);
|
tls_dma_free(sdio_spi_dma_channel);
|
||||||
tls_os_sem_release(sdio_spi_dma_ready_flag);
|
extern lv_disp_drv_t display_driver;
|
||||||
|
lv_disp_flush_ready(&display_driver);
|
||||||
|
//tls_os_sem_release(sdio_spi_dma_ready_flag);
|
||||||
|
|
||||||
//tls_mem_free(sdio_spi_dma_temp_buf);
|
//tls_mem_free(sdio_spi_dma_temp_buf);
|
||||||
//free(sdio_spi_dma_temp_buf);
|
//free(sdio_spi_dma_temp_buf);
|
||||||
// 等待信号量 直到上一次DMA数据发送完成
|
// 等待信号量 直到上一次DMA数据发送完成
|
||||||
sdio_spi_dma_ready = true;
|
// sdio_spi_dma_ready = true;
|
||||||
// printf("--->tls_os_sem_release [%s:%d]\r\n",__func__,__LINE__);
|
// printf("--->tls_os_sem_release [%s:%d]\r\n",__func__,__LINE__);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static u32 tmpbuff[2880];
|
//static u32 tmpbuff[5760];
|
||||||
|
|
||||||
void mmc_sdio_driver_write_dma_async(u32 *data, u32 dataLengthInBytes)
|
void mmc_sdio_driver_write_dma_async(u32 *data, u32 dataLengthInBytes)
|
||||||
{
|
{
|
||||||
// Wait for the semaphore until the last DMA data transmission is completed
|
// Wait for the semaphore until the last DMA data transmission is completed
|
||||||
// printf("--->tls_os_sem_acquire [%s:%d]\r\n",__func__,__LINE__);
|
// printf("--->tls_os_sem_acquire [%s:%d]\r\n",__func__,__LINE__);
|
||||||
tls_os_sem_acquire(sdio_spi_dma_ready_flag, 0);
|
/*tls_os_sem_acquire(sdio_spi_dma_ready_flag, 0);
|
||||||
sdio_spi_dma_ready = false;
|
sdio_spi_dma_ready = false;*/
|
||||||
// printf("--->%s:%d\r\n",__func__,__LINE__);
|
// printf("--->%s:%d\r\n",__func__,__LINE__);
|
||||||
|
|
||||||
// printf("--->w buf_size:%d\n", len);
|
// printf("--->w buf_size:%d\n", len);
|
||||||
@ -107,7 +110,8 @@ void mmc_sdio_driver_write_dma_async(u32 *data, u32 dataLengthInBytes)
|
|||||||
// printf("Len not aligned\n");
|
// printf("Len not aligned\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
/*sdio_spi_dma_temp_buf = malloc(dataLengthInBytes);//tls_mem_alloc(dataLengthInBytes);
|
//sdio_spi_dma_temp_buf = tls_mem_alloc(dataLengthInBytes);
|
||||||
|
/*sdio_spi_dma_temp_buf = malloc(dataLengthInBytes);
|
||||||
|
|
||||||
if (sdio_spi_dma_temp_buf == NULL)
|
if (sdio_spi_dma_temp_buf == NULL)
|
||||||
{
|
{
|
||||||
@ -117,7 +121,7 @@ void mmc_sdio_driver_write_dma_async(u32 *data, u32 dataLengthInBytes)
|
|||||||
memcpy(sdio_spi_dma_temp_buf, data, dataLengthInBytes);
|
memcpy(sdio_spi_dma_temp_buf, data, dataLengthInBytes);
|
||||||
|
|
||||||
sdio_spi_dma_buf_addr = sdio_spi_dma_temp_buf;*/
|
sdio_spi_dma_buf_addr = sdio_spi_dma_temp_buf;*/
|
||||||
memcpy(tmpbuff, data, dataLengthInBytes);
|
//memcpy(tmpbuff, data, dataLengthInBytes);
|
||||||
sdio_spi_dma_buf_size = dataLengthInBytes;
|
sdio_spi_dma_buf_size = dataLengthInBytes;
|
||||||
|
|
||||||
while (1)
|
while (1)
|
||||||
@ -129,7 +133,7 @@ void mmc_sdio_driver_write_dma_async(u32 *data, u32 dataLengthInBytes)
|
|||||||
SDIO_HOST->BUF_CTL = 0x4000; // disable dma,
|
SDIO_HOST->BUF_CTL = 0x4000; // disable dma,
|
||||||
sdio_spi_dma_channel = tls_dma_request(0, 0);
|
sdio_spi_dma_channel = tls_dma_request(0, 0);
|
||||||
DMA_CHNLCTRL_REG(sdio_spi_dma_channel) = DMA_CHNL_CTRL_CHNL_OFF;
|
DMA_CHNLCTRL_REG(sdio_spi_dma_channel) = DMA_CHNL_CTRL_CHNL_OFF;
|
||||||
DMA_SRCADDR_REG(sdio_spi_dma_channel) = (unsigned int)tmpbuff;//sdio_spi_dma_buf_addr;
|
DMA_SRCADDR_REG(sdio_spi_dma_channel) = (unsigned int)data;//sdio_spi_dma_buf_addr;
|
||||||
DMA_DESTADDR_REG(sdio_spi_dma_channel) = (unsigned int)SDIO_HOST->DATA_BUF;
|
DMA_DESTADDR_REG(sdio_spi_dma_channel) = (unsigned int)SDIO_HOST->DATA_BUF;
|
||||||
/*u32 bufsize = sdio_spi_dma_buf_size;
|
/*u32 bufsize = sdio_spi_dma_buf_size;
|
||||||
if (bufsize > 65532)
|
if (bufsize > 65532)
|
||||||
@ -165,6 +169,16 @@ void mmc_sdio_driver_write_one(u8 byte)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void mmc_sdio_driver_write(const u8 * bytes, u16 len)
|
||||||
|
{
|
||||||
|
SDIO_HOST->BUF_CTL = 0x4820;
|
||||||
|
memcpy(SDIO_HOST->DATA_BUF, bytes, len);
|
||||||
|
|
||||||
|
SDIO_HOST->MMC_BYTECNTL = len;
|
||||||
|
SDIO_HOST->MMC_IO = 0x01;
|
||||||
|
while (SDIO_HOST->MMC_IO & 0x01);
|
||||||
|
}
|
||||||
|
|
||||||
void mmc_sdio_driver_wait_write_dma_ready(void)
|
void mmc_sdio_driver_wait_write_dma_ready(void)
|
||||||
{
|
{
|
||||||
while(!sdio_spi_dma_ready)
|
while(!sdio_spi_dma_ready)
|
||||||
|
@ -12,6 +12,8 @@ void mmc_sdio_driver_write_dma_async(u32 *data, u32 dataLengthInBytes);
|
|||||||
/* Sends one byte of data to the slave */
|
/* Sends one byte of data to the slave */
|
||||||
void mmc_sdio_driver_write_one(u8 byte);
|
void mmc_sdio_driver_write_one(u8 byte);
|
||||||
|
|
||||||
|
void mmc_sdio_driver_write(const u8 * bytes, u16 len);
|
||||||
|
|
||||||
/* Blocks the current task until the write through DMA is available again */
|
/* Blocks the current task until the write through DMA is available again */
|
||||||
void mmc_sdio_driver_wait_write_dma_ready(void);
|
void mmc_sdio_driver_wait_write_dma_ready(void);
|
||||||
|
|
||||||
|
@ -49,7 +49,8 @@
|
|||||||
#define LV_MEM_CUSTOM 0
|
#define LV_MEM_CUSTOM 0
|
||||||
#if LV_MEM_CUSTOM == 0
|
#if LV_MEM_CUSTOM == 0
|
||||||
/*Size of the memory available for `lv_mem_alloc()` in bytes (>= 2kB)*/
|
/*Size of the memory available for `lv_mem_alloc()` in bytes (>= 2kB)*/
|
||||||
#define LV_MEM_SIZE (20 * 1024U) /*[bytes]*/
|
//#define LV_MEM_SIZE (30 * 1024U) /*[bytes]*/
|
||||||
|
#define LV_MEM_SIZE (48 * 1024U)
|
||||||
|
|
||||||
/*Set an address for the memory pool instead of allocating it as a normal array. Can be in external SRAM too.*/
|
/*Set an address for the memory pool instead of allocating it as a normal array. Can be in external SRAM too.*/
|
||||||
#define LV_MEM_ADR 0 /*0: unused*/
|
#define LV_MEM_ADR 0 /*0: unused*/
|
||||||
@ -78,10 +79,10 @@
|
|||||||
*====================*/
|
*====================*/
|
||||||
|
|
||||||
/*Default display refresh period. LVG will redraw changed areas with this period time*/
|
/*Default display refresh period. LVG will redraw changed areas with this period time*/
|
||||||
#define LV_DISP_DEF_REFR_PERIOD 16 /*[ms]*/
|
#define LV_DISP_DEF_REFR_PERIOD 10 /*[ms]*/
|
||||||
|
|
||||||
/*Input device read period in milliseconds*/
|
/*Input device read period in milliseconds*/
|
||||||
#define LV_INDEV_DEF_READ_PERIOD 16 /*[ms]*/
|
#define LV_INDEV_DEF_READ_PERIOD 20 /*[ms]*/
|
||||||
|
|
||||||
/*Use a custom tick source that tells the elapsed time in milliseconds.
|
/*Use a custom tick source that tells the elapsed time in milliseconds.
|
||||||
*It removes the need to manually update the tick with `lv_tick_inc()`)*/
|
*It removes the need to manually update the tick with `lv_tick_inc()`)*/
|
||||||
@ -219,7 +220,7 @@
|
|||||||
*-----------*/
|
*-----------*/
|
||||||
|
|
||||||
/*Enable the log module*/
|
/*Enable the log module*/
|
||||||
#define LV_USE_LOG 1
|
#define LV_USE_LOG 0
|
||||||
#if LV_USE_LOG
|
#if LV_USE_LOG
|
||||||
|
|
||||||
/*How important log should be added:
|
/*How important log should be added:
|
||||||
@ -724,7 +725,7 @@
|
|||||||
====================*/
|
====================*/
|
||||||
|
|
||||||
/*Show some widget. It might be required to increase `LV_MEM_SIZE` */
|
/*Show some widget. It might be required to increase `LV_MEM_SIZE` */
|
||||||
#define LV_USE_DEMO_WIDGETS 0
|
#define LV_USE_DEMO_WIDGETS 1
|
||||||
#if LV_USE_DEMO_WIDGETS
|
#if LV_USE_DEMO_WIDGETS
|
||||||
#define LV_DEMO_WIDGETS_SLIDESHOW 0
|
#define LV_DEMO_WIDGETS_SLIDESHOW 0
|
||||||
#endif
|
#endif
|
||||||
|
@ -70,7 +70,7 @@
|
|||||||
|
|
||||||
#define configUSE_PREEMPTION 1
|
#define configUSE_PREEMPTION 1
|
||||||
#define configUSE_IDLE_HOOK 1 //ʹ<>ÿ<EFBFBD><C3BF>й<EFBFBD><D0B9><EFBFBD>
|
#define configUSE_IDLE_HOOK 1 //ʹ<>ÿ<EFBFBD><C3BF>й<EFBFBD><D0B9><EFBFBD>
|
||||||
#define configUSE_TICK_HOOK 0
|
#define configUSE_TICK_HOOK 1
|
||||||
|
|
||||||
#define configCPU_CLOCK_HZ ( ( unsigned long ) 40000000 ) /* =12.0MHz xtal multiplied by 5 using the PLL. *///???????????????
|
#define configCPU_CLOCK_HZ ( ( unsigned long ) 40000000 ) /* =12.0MHz xtal multiplied by 5 using the PLL. *///???????????????
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user