lock_lfvx/bk_idk/middleware/driver/lcd/lcd_qspi_driver.c
2025-10-10 16:07:00 +08:00

774 lines
27 KiB
C
Executable File

// Copyright 2020-2021 Beken
//
// 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 <common/bk_include.h>
#include <os/mem.h>
#include <os/str.h>
#include <driver/dma2d.h>
#include <driver/qspi.h>
#include <driver/qspi_types.h>
#include <driver/lcd_types.h>
#include <driver/lcd_qspi.h>
#include <driver/media_types.h>
#include "gpio_driver.h"
#include <driver/gpio.h>
#include "bk_misc.h"
#include <driver/dma.h>
#include "bk_general_dma.h"
#include <components/log.h>
#define LCD_QSPI_TAG "lcd_qspi"
#define LCD_QSPI_LOGI(...) BK_LOGI(LCD_QSPI_TAG, ##__VA_ARGS__)
#define LCD_QSPI_LOGW(...) BK_LOGW(LCD_QSPI_TAG, ##__VA_ARGS__)
#define LCD_QSPI_LOGE(...) BK_LOGE(LCD_QSPI_TAG, ##__VA_ARGS__)
#define LCD_QSPI_LOGD(...) BK_LOGD(LCD_QSPI_TAG, ##__VA_ARGS__)
#if CONFIG_SOC_BK7256XX
#define LCD_QSPI_DATA_ADDR 0x68000000
#define LCD_QSPI_RESET_PIN GPIO_47
#endif
#if CONFIG_SOC_BK7236XX
#define LCD_QSPI0_DATA_ADDR 0x64000000
#define LCD_QSPI1_DATA_ADDR 0x68000000
#define LCD_QSPI_RESET_PIN GPIO_40
#endif
static qspi_driver_t s_lcd_qspi[SOC_QSPI_UNIT_NUM] = {
{
.hal.hw = (qspi_hw_t *)(SOC_QSPI0_REG_BASE),
},
#if (SOC_QSPI_UNIT_NUM > 1)
{
.hal.hw = (qspi_hw_t *)(SOC_QSPI1_REG_BASE),
}
#endif
};
static beken_semaphore_t lcd_qspi_semaphore = NULL;
#if (CONFIG_SOC_BK7256XX)
#if (USE_HAL_DMA2D_REGISTER_CALLBACKS == 1)
static void dma2d_transfer_complete_isr(void)
{
bk_err_t ret = BK_OK;
bk_dma2d_int_status_clear(DMA2D_TRANS_COMPLETE_STATUS);
ret = rtos_set_semaphore(&lcd_qspi_semaphore);
if (ret != BK_OK) {
LCD_QSPI_LOGE("lcd qspi semaphore set failed\r\n");
return;
}
}
#endif
#elif CONFIG_SOC_BK7236XX
static dma_id_t lcd_qspi_dma_id = DMA_ID_MAX;
static uint32_t dma_repeat_once_len = 0;
extern media_debug_t *media_debug;
static void lcd_qspi_dma_finish_isr(void)
{
bk_err_t ret = BK_OK;
uint32_t value = 0;
value = bk_dma_get_repeat_wr_pause(lcd_qspi_dma_id);
if (value) {
media_debug->isr_lcd++;
bk_dma_stop(lcd_qspi_dma_id);
//bk_lcd_qspi_quad_write_stop();
ret = rtos_set_semaphore(&lcd_qspi_semaphore);
if (ret != BK_OK) {
LCD_QSPI_LOGE("lcd qspi semaphore set failed\r\n");
return;
}
}
}
#endif
static bk_err_t lcd_qspi_driver_init(qspi_id_t qspi_id, lcd_qspi_clk_t clk)
{
qspi_config_t lcd_qspi_config;
os_memset(&lcd_qspi_config, 0, sizeof(lcd_qspi_config));
os_memset(&s_lcd_qspi, 0, sizeof(s_lcd_qspi));
s_lcd_qspi[qspi_id].hal.id = qspi_id;
qspi_hal_init(&s_lcd_qspi[qspi_id].hal);
switch (clk) {
case LCD_QSPI_80M:
lcd_qspi_config.src_clk = QSPI_SCLK_480M;
lcd_qspi_config.src_clk_div = 5;
BK_LOG_ON_ERR(bk_qspi_init(qspi_id, &lcd_qspi_config));
break;
case LCD_QSPI_64M:
lcd_qspi_config.src_clk = QSPI_SCLK_320M;
lcd_qspi_config.src_clk_div = 4;
BK_LOG_ON_ERR(bk_qspi_init(qspi_id, &lcd_qspi_config));
break;
case LCD_QSPI_60M:
lcd_qspi_config.src_clk = QSPI_SCLK_480M;
lcd_qspi_config.src_clk_div = 7;
BK_LOG_ON_ERR(bk_qspi_init(qspi_id, &lcd_qspi_config));
break;
case LCD_QSPI_53M:
lcd_qspi_config.src_clk = QSPI_SCLK_480M;
lcd_qspi_config.src_clk_div = 8;
BK_LOG_ON_ERR(bk_qspi_init(qspi_id, &lcd_qspi_config));
break;
case LCD_QSPI_48M:
lcd_qspi_config.src_clk = QSPI_SCLK_480M;
lcd_qspi_config.src_clk_div = 9;
BK_LOG_ON_ERR(bk_qspi_init(qspi_id, &lcd_qspi_config));
break;
case LCD_QSPI_40M:
lcd_qspi_config.src_clk = QSPI_SCLK_480M;
lcd_qspi_config.src_clk_div = 11;
BK_LOG_ON_ERR(bk_qspi_init(qspi_id, &lcd_qspi_config));
break;
case LCD_QSPI_32M:
lcd_qspi_config.src_clk = QSPI_SCLK_320M;
lcd_qspi_config.src_clk_div = 9;
BK_LOG_ON_ERR(bk_qspi_init(qspi_id, &lcd_qspi_config));
break;
case LCD_QSPI_30M:
lcd_qspi_config.src_clk = QSPI_SCLK_480M;
lcd_qspi_config.src_clk_div = 15;
BK_LOG_ON_ERR(bk_qspi_init(qspi_id, &lcd_qspi_config));
break;
default:
lcd_qspi_config.src_clk = QSPI_SCLK_480M;
lcd_qspi_config.src_clk_div = 11;
BK_LOG_ON_ERR(bk_qspi_init(qspi_id, &lcd_qspi_config));
break;
}
return BK_OK;
}
static bk_err_t lcd_qspi_hardware_reset(void)
{
gpio_dev_unmap(LCD_QSPI_RESET_PIN);
gpio_dev_map(LCD_QSPI_RESET_PIN, 0);
bk_gpio_enable_pull(LCD_QSPI_RESET_PIN);
bk_gpio_pull_up(LCD_QSPI_RESET_PIN);
rtos_delay_milliseconds(10);
bk_gpio_pull_down(LCD_QSPI_RESET_PIN);
rtos_delay_milliseconds(10);
bk_gpio_pull_up(LCD_QSPI_RESET_PIN);
rtos_delay_milliseconds(120);
return BK_OK;
}
static bk_err_t lcd_qspi_quad_write_enable(qspi_id_t qspi_id)
{
qspi_hal_set_cmd_a_l(&s_lcd_qspi[qspi_id].hal, 0x00002C00);
qspi_hal_set_cmd_a_h(&s_lcd_qspi[qspi_id].hal, 0x10000100);
qspi_hal_set_cmd_a_cfg1(&s_lcd_qspi[qspi_id].hal, 0xEAAA);
qspi_hal_set_cmd_a_cfg2(&s_lcd_qspi[qspi_id].hal, 0x80008000);
return BK_OK;
}
#if CONFIG_SH8601A_PARTIAL
/*设置部分显示区域坐标函数*/
void sh8601a_set_display_mem_area(uint16 xs, uint16 xe, uint16 ys, uint16 ye)
{
uint16 xs_l, xs_h, xe_l, xe_h;
uint16 ys_l, ys_h, ye_l, ye_h;
xs_h = xs >> 8;
xs_l = xs & 0xff;
xe_h = xe >> 8;
xe_l = xe & 0xff;
ys_h = ys >> 8;
ys_l = ys & 0xff;
ye_h = ye >> 8;
ye_l = ye & 0xff;
uint8_t param_clumn[4] = {xs_h, xs_l, xe_h, xe_l};
uint8_t param_row[4]= {ys_h, ys_l, ye_h, ye_l};
// LCD_QSPI_LOGE("xs_h:0x%x, xs_l:0x%x, xe_h:0x%x, xe_l:0x%x\r\n",xs_h, xs_l, xe_h, xe_l);
// LCD_QSPI_LOGE("ys_h:0x%x, ys_l:0x%x, ye_h:0x%x, ye_l:0x%x\r\n",ys_h, ys_l, ye_h, ye_l);
bk_lcd_qspi_send_cmd(0x2, 0x30, param_clumn,4);
bk_lcd_qspi_send_cmd(0x2, 0x31, param_row,4);
}
#endif
static bk_err_t lcd_qspi_common_init(qspi_id_t qspi_id)
{
bk_err_t ret = BK_OK;
lcd_qspi_hardware_reset();
ret = rtos_init_semaphore(&lcd_qspi_semaphore, 1);
if (ret != kNoErr) {
LCD_QSPI_LOGE("lcd qspi semaphore init failed.\r\n");
return BK_FAIL;
}
#if (CONFIG_SOC_BK7256XX)
ret = bk_dma2d_driver_init();
if (ret != BK_OK) {
LCD_QSPI_LOGE("dma2d driver init failed!\r\n");
return BK_FAIL;
}
#if (USE_HAL_DMA2D_REGISTER_CALLBACKS == 1)
bk_dma2d_register_int_callback_isr(DMA2D_TRANS_COMPLETE_ISR, dma2d_transfer_complete_isr);
if (ret != BK_OK) {
LCD_QSPI_LOGE("dma2d interrupt register failed!\r\n");
return BK_FAIL;
}
bk_dma2d_int_enable(DMA2D_TRANS_COMPLETE, 1);
#endif
#elif CONFIG_SOC_BK7236XX
ret = bk_dma_driver_init();
if (ret != BK_OK) {
LCD_QSPI_LOGE("dma driver init failed!\r\n");
return BK_FAIL;
}
lcd_qspi_dma_id = bk_dma_alloc(DMA_DEV_DTCM);
if ((lcd_qspi_dma_id < DMA_ID_0) || (lcd_qspi_dma_id >= DMA_ID_MAX)) {
LCD_QSPI_LOGE("lcd qspi dma malloc failed!\r\n");
return BK_FAIL;
}
#if (CONFIG_SPE)
bk_dma_set_src_sec_attr(lcd_qspi_dma_id, DMA_ATTR_SEC);
bk_dma_set_dest_sec_attr(lcd_qspi_dma_id, DMA_ATTR_SEC);
bk_dma_set_dest_burst_len(lcd_qspi_dma_id, BURST_LEN_INC16);
bk_dma_set_src_burst_len(lcd_qspi_dma_id, BURST_LEN_INC16);
#endif
#endif
lcd_qspi_quad_write_enable(qspi_id);
return BK_OK;
}
static bk_err_t lcd_qspi_common_deinit(void)
{
bk_err_t ret = BK_OK;
ret = rtos_deinit_semaphore(&lcd_qspi_semaphore);
if (ret != kNoErr) {
LCD_QSPI_LOGE("lcd qspi semaphore deinit failed.\r\n");
return BK_FAIL;
}
#if (CONFIG_SOC_BK7256XX)
bk_dma2d_driver_deinit();
#elif CONFIG_SOC_BK7236XX
bk_dma_free(DMA_DEV_DTCM, lcd_qspi_dma_id);
BK_LOG_ON_ERR(bk_dma_driver_deinit());
#endif
return BK_OK;
}
#if (CONFIG_SOC_BK7256XX)
static void bk_lcd_qspi_dma2d_fill(uint32_t width, uint32_t height, uint32_t color, bool data_reverse)
{
dma2d_config_t dma2d_config = {0};
dma2d_config.init.mode = DMA2D_R2M; /**< Mode Register to Memory */
dma2d_config.init.color_mode = DMA2D_OUTPUT_RGB888; /**< DMA2D Output color mode is RGB888 */
dma2d_config.init.output_offset = 0; /**< offset in output */
dma2d_config.init.red_blue_swap = DMA2D_RB_REGULAR; /**< No R&B swap for the output image */
dma2d_config.init.alpha_inverted = DMA2D_REGULAR_ALPHA; /**< No alpha inversion for the output image */
dma2d_config.init.out_byte_by_byte_reverse = data_reverse;
bk_dma2d_init(&dma2d_config);
bk_dma2d_transfer_config(&dma2d_config, color, LCD_QSPI_DATA_ADDR, width, height);
bk_dma2d_start_transfer();
}
static void bk_lcd_qspi_dma2d_memcpy(uint32_t *Psrc, uint32_t xsize, uint32_t ysize, bool data_reverse)
{
dma2d_config_t dma2d_config = {0};
#if CONFIG_LVGL
#if (CONFIG_LV_COLOR_DEPTH == 32)
dma2d_config.init.mode = DMA2D_M2M_PFC;
dma2d_config.layer_cfg[DMA2D_FOREGROUND_LAYER].input_color_mode = DMA2D_INPUT_ARGB8888;
dma2d_config.init.out_byte_by_byte_reverse = data_reverse;
dma2d_config.init.color_mode = DMA2D_OUTPUT_RGB888; /**< Output color mode is RGB888 */
#else
dma2d_config.init.mode = DMA2D_M2M; /**< Mode Memory To Memory */
dma2d_config.layer_cfg[DMA2D_FOREGROUND_LAYER].input_color_mode = DMA2D_INPUT_RGB565; /**< Input color is RGB565 */
dma2d_config.init.color_mode = DMA2D_OUTPUT_RGB565; /**< Output color mode is RGB565 */
#endif
#else
#if (CONFIG_LCD_QSPI_COLOR_DEPTH_BYTE == 2)
dma2d_config.init.mode = DMA2D_M2M; /**< Mode Memory To Memory */
dma2d_config.layer_cfg[DMA2D_FOREGROUND_LAYER].input_color_mode = DMA2D_INPUT_RGB565; /**< Input color is RGB565 */
dma2d_config.init.color_mode = DMA2D_OUTPUT_RGB565; /**< Output color mode is RGB565 */
#else
dma2d_config.init.mode = DMA2D_M2M; /**< Mode Memory To Memory */
dma2d_config.layer_cfg[DMA2D_FOREGROUND_LAYER].input_color_mode = DMA2D_INPUT_RGB888; /**< Input color is RGB888 */
dma2d_config.init.color_mode = DMA2D_OUTPUT_RGB888; /**< Output color mode is RGB888 */
#endif
#endif
dma2d_config.layer_cfg[DMA2D_FOREGROUND_LAYER].red_blue_swap = DMA2D_RB_REGULAR; /**< No R&B swap for the input image */
dma2d_config.init.output_offset = 0; /**< No offset on output */
dma2d_config.init.red_blue_swap = DMA2D_RB_REGULAR; /**< No R&B swap for the output image */
dma2d_config.init.alpha_inverted = DMA2D_REGULAR_ALPHA; /**< No alpha inversion for the output image */
dma2d_config.layer_cfg[DMA2D_FOREGROUND_LAYER].alpha_mode = DMA2D_NO_MODIF_ALPHA; /**< Keep original Alpha from RGB888 input */
dma2d_config.layer_cfg[DMA2D_FOREGROUND_LAYER].input_alpha = 0xFF; /**< Fully opaque */
dma2d_config.layer_cfg[DMA2D_FOREGROUND_LAYER].input_offset = 0; /**< No offset in input */
dma2d_config.layer_cfg[DMA2D_FOREGROUND_LAYER].alpha_inverted = DMA2D_REGULAR_ALPHA; /**< No alpha inversion for the input image */
bk_dma2d_init(&dma2d_config);
bk_dma2d_layer_config(&dma2d_config, DMA2D_FOREGROUND_LAYER);
bk_dma2d_transfer_config(&dma2d_config, (uint32_t)Psrc, LCD_QSPI_DATA_ADDR, xsize, ysize);
bk_dma2d_start_transfer();
}
#endif
static bk_err_t lcd_qspi_reg_data_convert(qspi_id_t qspi_id, uint8_t *data, uint32_t data_len)
{
uint32_t data_buffer[data_len];
uint8_t i, j, data_tmp1;
uint8_t data_tmp2[4];
bk_qspi_read(qspi_id, data_buffer, data_len * 4);
for (i = 0; i < data_len; i++) {
for (j = 0; j < 4; j++) {
data_tmp1 = (data_buffer[i] >> ((j * 8) + 4)) & 0x1;
data_tmp2[j] = (data_tmp1 << 1) | ((data_buffer[i] >> (j * 8)) & 0x1);
}
data[i] = (data_tmp2[0] << 6) | (data_tmp2[1] << 4) | (data_tmp2[2] << 2) | (data_tmp2[3]);
}
return BK_OK;
}
bk_err_t bk_lcd_qspi_read_data(qspi_id_t qspi_id, uint8_t *data, const lcd_device_t *device, uint8_t regist_addr, uint8_t data_len)
{
qspi_hal_set_cmd_d_h(&s_lcd_qspi[qspi_id].hal, 0);
qspi_hal_set_cmd_d_cfg1(&s_lcd_qspi[qspi_id].hal, 0);
qspi_hal_set_cmd_d_cfg2(&s_lcd_qspi[qspi_id].hal, 0);
qspi_hal_set_cmd_d_h(&s_lcd_qspi[qspi_id].hal, (regist_addr << 16 | device->qspi->reg_read_cmd) & 0xFF00FF);
qspi_hal_set_cmd_d_cfg1(&s_lcd_qspi[qspi_id].hal, 0x300);
qspi_hal_set_cmd_d_data_line(&s_lcd_qspi[qspi_id].hal, 2);
qspi_hal_set_cmd_d_data_length(&s_lcd_qspi[qspi_id].hal, data_len * 4);
qspi_hal_set_cmd_d_dummy_clock(&s_lcd_qspi[qspi_id].hal, device->qspi->reg_read_config.dummy_clk);
qspi_hal_set_cmd_d_dummy_mode(&s_lcd_qspi[qspi_id].hal, device->qspi->reg_read_config.dummy_mode);
qspi_hal_cmd_d_start(&s_lcd_qspi[qspi_id].hal);
qspi_hal_wait_cmd_done(&s_lcd_qspi[qspi_id].hal);
lcd_qspi_reg_data_convert(qspi_id, data, data_len);
return BK_OK;
}
bk_err_t bk_lcd_qspi_send_cmd(qspi_id_t qspi_id, uint8_t write_cmd, uint8_t cmd, const uint8_t *data, uint8_t data_len)
{
qspi_hal_set_cmd_c_l(&s_lcd_qspi[qspi_id].hal, 0);
qspi_hal_set_cmd_c_h(&s_lcd_qspi[qspi_id].hal, 0);
qspi_hal_set_cmd_c_cfg1(&s_lcd_qspi[qspi_id].hal, 0);
qspi_hal_set_cmd_c_cfg2(&s_lcd_qspi[qspi_id].hal, 0);
if (data_len == 0) {
qspi_hal_set_cmd_c_h(&s_lcd_qspi[qspi_id].hal, (cmd << 16 | write_cmd) & 0xFF00FF);
} else if (data_len > 0 && data_len <= 4) {
uint32_t value = 0;
for (uint8_t i = 0; i < data_len; i++) {
value = value | (data[i] << (i * 8));
}
qspi_hal_set_cmd_c_l(&s_lcd_qspi[qspi_id].hal, value);
qspi_hal_set_cmd_c_h(&s_lcd_qspi[qspi_id].hal, (cmd << 16 | write_cmd) & 0xFF00FF);
} else if (data_len > 4 && data_len != 0xFF) {
qspi_hal_set_cmd_c_h(&s_lcd_qspi[qspi_id].hal, (cmd << 16 | write_cmd) & 0xFF00FF);
qspi_hal_set_cmd_c_cfg1(&s_lcd_qspi[qspi_id].hal, 0x300);
qspi_hal_set_cmd_c_cfg2(&s_lcd_qspi[qspi_id].hal, data_len << 2);
bk_qspi_write(qspi_id, data, data_len);
qspi_hal_cmd_c_start(&s_lcd_qspi[qspi_id].hal);
qspi_hal_wait_cmd_done(&s_lcd_qspi[qspi_id].hal);
qspi_hal_set_cmd_c_cfg1(&s_lcd_qspi[qspi_id].hal, 0);
qspi_hal_set_cmd_c_cfg2(&s_lcd_qspi[qspi_id].hal, 0);
return BK_OK;
}
qspi_hal_set_cmd_c_cfg1(&s_lcd_qspi[qspi_id].hal, 0x3 << ((data_len + 4) * 2));
qspi_hal_cmd_c_start(&s_lcd_qspi[qspi_id].hal);
qspi_hal_wait_cmd_done(&s_lcd_qspi[qspi_id].hal);
return BK_OK;
}
bk_err_t bk_lcd_qspi_quad_write_start(qspi_id_t qspi_id, lcd_qspi_write_config_t reg_config, bool addr_is_4wire)
{
uint32_t cmd_c_h = 0;
qspi_hal_force_spi_cs_low_enable(&s_lcd_qspi[qspi_id].hal);
qspi_hal_set_cmd_c_h(&s_lcd_qspi[qspi_id].hal, 0);
for (uint8_t i = 0; i < reg_config.cmd_len; i++) {
cmd_c_h = qspi_hal_get_cmd_c_h(&s_lcd_qspi[qspi_id].hal);
cmd_c_h |= ((reg_config.cmd[i]) << i * 8);
qspi_hal_set_cmd_c_h(&s_lcd_qspi[qspi_id].hal, cmd_c_h);
}
if (addr_is_4wire) {
qspi_hal_set_cmd_c_cfg1(&s_lcd_qspi[qspi_id].hal, 0x3A8);
} else {
qspi_hal_set_cmd_c_cfg1(&s_lcd_qspi[qspi_id].hal, 0x300);
}
qspi_hal_cmd_c_start(&s_lcd_qspi[qspi_id].hal);
qspi_hal_wait_cmd_done(&s_lcd_qspi[qspi_id].hal);
#if (CONFIG_SOC_BK7236XX)
qspi_hal_io_cpu_mem_select(&s_lcd_qspi[qspi_id].hal, 1);
#endif
qspi_hal_disable_cmd_sck_enable(&s_lcd_qspi[qspi_id].hal);
return BK_OK;
}
bk_err_t bk_lcd_qspi_quad_write_stop(qspi_id_t qspi_id)
{
qspi_hal_disable_cmd_sck_disable(&s_lcd_qspi[qspi_id].hal);
qspi_hal_force_spi_cs_low_disable(&s_lcd_qspi[qspi_id].hal);
#if (CONFIG_SOC_BK7236XX)
qspi_hal_io_cpu_mem_select(&s_lcd_qspi[qspi_id].hal, 0);
#endif
return BK_OK;
}
#if CONFIG_SOC_BK7236XX
static bk_err_t lcd_qspi_refresh_by_line_lcd_head_config(qspi_id_t qspi_id, const lcd_device_t *device)
{
uint8_t *cmd = NULL;
uint32_t head_cmd[4];
uint8_t i;
cmd = device->qspi->pixel_write_config.cmd;
for (i = 0; i < device->qspi->pixel_write_config.cmd_len; i++) {
if (0 == cmd[i]) {
head_cmd[i] = 0x0;
continue;
} else {
cmd[i] = ((cmd[i] >> 4) & 0x0F) | ((cmd[i] << 4) & 0xF0);
cmd[i] = ((cmd[i] >> 2) & 0x33) | ((cmd[i] << 2) & 0xCC);
cmd[i] = ((cmd[i] >> 1) & 0x55) | ((cmd[i] << 1) & 0xAA);
head_cmd[i] = ((cmd[i] << 21) & 0x10000000) | ((cmd[i] << 18) & 0x01000000) |
((cmd[i] << 15) & 0x00100000) | ((cmd[i] << 12) & 0x00010000) |
((cmd[i] << 9) & 0x00001000) | ((cmd[i] << 6) & 0x00000100) |
((cmd[i] << 3) & 0x00000010) | (cmd[i] & 0x00000001);
}
}
qspi_hal_enable_soft_reset(&s_lcd_qspi[qspi_id].hal);
qspi_hal_set_lcd_head_cmd0(&s_lcd_qspi[qspi_id].hal, head_cmd[0]);
qspi_hal_set_lcd_head_cmd1(&s_lcd_qspi[qspi_id].hal, head_cmd[1]);
qspi_hal_set_lcd_head_cmd2(&s_lcd_qspi[qspi_id].hal, head_cmd[2]);
qspi_hal_set_lcd_head_cmd3(&s_lcd_qspi[qspi_id].hal, head_cmd[3]);
qspi_hal_set_lcd_head_resolution(&s_lcd_qspi[qspi_id].hal, device->qspi->refresh_config.line_len * 2, device->ppi & 0xFFFF);
qspi_hal_enable_lcd_head_selection_without_ram(&s_lcd_qspi[qspi_id].hal);
qspi_hal_set_lcd_head_len(&s_lcd_qspi[qspi_id].hal, 0x20);
qspi_hal_set_lcd_head_dly(&s_lcd_qspi[qspi_id].hal, (device->qspi->clk >> 1) + 6);
return BK_OK;
}
bk_err_t lcd_qspi_get_dma_repeat_once_len(const lcd_device_t *device)
{
uint32_t len = 0;
uint32_t value = 0;
uint8_t i = 0;
for (i = 4; i < 13; i++) {
len = device->qspi->frame_len / i;
if (len <= 0x10000) {
value = device->qspi->frame_len % i;
if (!value) {
return len;
}
}
}
LCD_QSPI_LOGE("%s Error dma length, please check the resolution of qspi lcd\r\n", __func__);
return len;
}
#endif
bk_err_t bk_lcd_qspi_init(qspi_id_t qspi_id, const lcd_device_t *device)
{
bk_err_t ret = BK_OK;
if (device == NULL) {
LCD_QSPI_LOGE("lcd qspi device not found\r\n");
return BK_FAIL;
}
ret = lcd_qspi_driver_init(qspi_id, device->qspi->clk);
if (ret != BK_OK) {
LCD_QSPI_LOGE("lcd qspi driver init failed!\r\n");
return ret;
}
ret = lcd_qspi_common_init(qspi_id);
if (ret == BK_FAIL) {
LCD_QSPI_LOGE("lcd qspi common init failed!\r\n");
return ret;
}
#if CONFIG_SOC_BK7236XX
dma_repeat_once_len = lcd_qspi_get_dma_repeat_once_len(device);
LCD_QSPI_LOGI("dma_repeat_once_len = %d\r\n", dma_repeat_once_len);
bk_dma_set_transfer_len(lcd_qspi_dma_id, dma_repeat_once_len);
if (qspi_id == QSPI_ID_0) {
dma_set_dst_pause_addr(lcd_qspi_dma_id, LCD_QSPI0_DATA_ADDR + device->qspi->frame_len);
} else if (qspi_id == QSPI_ID_1) {
dma_set_dst_pause_addr(lcd_qspi_dma_id, LCD_QSPI1_DATA_ADDR + device->qspi->frame_len);
} else {
LCD_QSPI_LOGE("unsupported lcd qspi id\r\n");
return BK_FAIL;
}
qspi_hal_enable_soft_reset(&s_lcd_qspi[qspi_id].hal);
if (device->qspi->refresh_method == LCD_QSPI_REFRESH_BY_LINE) {
lcd_qspi_refresh_by_line_lcd_head_config(qspi_id, device);
}
#endif
if (device->qspi->init_cmd != NULL) {
const lcd_qspi_init_cmd_t *init = device->qspi->init_cmd;
for (uint32_t i = 0; i < device->qspi->device_init_cmd_len; i++) {
if (init->data_len == 0xff) {
rtos_delay_milliseconds(init->data[0]);
} else {
bk_lcd_qspi_send_cmd(qspi_id, device->qspi->reg_write_cmd, init->cmd, init->data, init->data_len);
}
init++;
}
} else {
LCD_QSPI_LOGE("lcd qspi device don't init\r\n");
return BK_FAIL;
}
return BK_OK;
}
bk_err_t bk_lcd_qspi_deinit(qspi_id_t qspi_id)
{
bk_err_t ret = BK_OK;
ret = lcd_qspi_common_deinit();
if (ret == BK_FAIL) {
LCD_QSPI_LOGE("lcd qspi common deinit failed!\r\n");
return ret;
}
BK_LOG_ON_ERR(bk_qspi_deinit(qspi_id));
return BK_OK;
}
static void lcd_qspi_disp_area_config_for_frame_refresh(qspi_id_t qspi_id, const lcd_device_t *device)
{
uint8_t column_value[4] = {0};
uint8_t row_value[4] = {0};
column_value[2] = (device->ppi >> 24) & 0xFF,
column_value[3] = ((device->ppi >> 16) & 0xFF) - 1,
row_value[2] = (device->ppi >> 8) & 0xFF;
row_value[3] = (device->ppi & 0xFF) - 1;
bk_lcd_qspi_send_cmd(qspi_id, device->qspi->reg_write_cmd, 0x2A, column_value, 4);
bk_lcd_qspi_send_cmd(qspi_id, device->qspi->reg_write_cmd, 0x2B, row_value, 4);
}
bk_err_t bk_lcd_qspi_send_data(qspi_id_t qspi_id, const lcd_device_t *device, uint32_t *data, uint32_t data_len)
{
bk_err_t ret = BK_OK;
#if (CONFIG_SOC_BK7256XX)
if (device->qspi->refresh_method == LCD_QSPI_REFRESH_BY_LINE) {
for (uint16_t i = 0; i < device->qspi->refresh_config.vsw; i++) {
bk_lcd_qspi_send_cmd(qspi_id, device->qspi->reg_write_cmd, device->qspi->refresh_config.vsync_cmd, NULL, 0);
delay_us(40);
}
for (uint16_t i = 0; i < device->qspi->refresh_config.hfp; i++) {
bk_lcd_qspi_send_cmd(qspi_id, device->qspi->reg_write_cmd, device->qspi->refresh_config.hsync_cmd, NULL, 0);
delay_us(40);
}
for (uint16_t i = 0; i < (device->ppi & 0xFFFF); i++) {
bk_lcd_qspi_quad_write_start(qspi_id, device->qspi->pixel_write_config, 0);
if (data_len == 1) {
bk_lcd_qspi_dma2d_fill(device->ppi >> 16, 1, *data, 0);
} else {
#if CONFIG_LVGL
#if (CONFIG_LV_COLOR_DEPTH == 32)
bk_lcd_qspi_dma2d_memcpy(data + i * (device->ppi >> 16), device->ppi >> 16, 1, 0);
#else
bk_lcd_qspi_dma2d_memcpy(data + i * (device->qspi->refresh_config.line_len >> 2), device->ppi >> 16, 1, 0);
#endif
#else
bk_lcd_qspi_dma2d_memcpy(data + i * (device->qspi->refresh_config.line_len >> 2), device->ppi >> 16, 1, 0);
#endif
}
#if (USE_HAL_DMA2D_REGISTER_CALLBACKS == 1)
ret = rtos_get_semaphore(&lcd_qspi_semaphore, 5);
if (ret != kNoErr) {
LCD_QSPI_LOGE("ret = %d, lcd qspi get semaphore failed!\r\n", ret);
return BK_FAIL;
}
#endif
bk_lcd_qspi_quad_write_stop(qspi_id);
}
for (uint16_t i = 0; i < device->qspi->refresh_config.hbp; i++) {
bk_lcd_qspi_send_cmd(qspi_id, device->qspi->reg_write_cmd, device->qspi->refresh_config.hsync_cmd, NULL, 0);
delay_us(40);
}
} else if (device->qspi->refresh_method == LCD_QSPI_REFRESH_BY_FRAME) {
bk_lcd_qspi_quad_write_start(qspi_id, device->qspi->pixel_write_config, 1);
if (data_len == 1) {
bk_lcd_qspi_dma2d_fill(device->ppi >> 16, device->ppi & 0xFFFF, *data, 1);
} else {
bk_lcd_qspi_dma2d_memcpy(data, device->ppi >> 16, device->ppi & 0xFFFF, 1);
}
#if (USE_HAL_DMA2D_REGISTER_CALLBACKS == 1)
ret = rtos_get_semaphore(&lcd_qspi_semaphore, 30);
if (ret != kNoErr) {
LCD_QSPI_LOGE("ret = %d, lcd qspi get semaphore failed!\r\n", ret);
return BK_FAIL;
}
#endif
bk_lcd_qspi_quad_write_stop(qspi_id);
} else {
LCD_QSPI_LOGE("invalid lcd qspi refresh method\r\n");
return BK_FAIL;
}
#elif (CONFIG_SOC_BK7236XX)
if (qspi_id == QSPI_ID_0) {
bk_dma_stateless_judgment_configuration((void *)LCD_QSPI0_DATA_ADDR, (void *)data, data_len, lcd_qspi_dma_id, (void *)lcd_qspi_dma_finish_isr);
} else if (qspi_id == QSPI_ID_1) {
bk_dma_stateless_judgment_configuration((void *)LCD_QSPI1_DATA_ADDR, (void *)data, data_len, lcd_qspi_dma_id, (void *)lcd_qspi_dma_finish_isr);
} else {
LCD_QSPI_LOGE("unsupported lcd qspi id\r\n");
return BK_FAIL;
}
dma_set_src_pause_addr(lcd_qspi_dma_id, (uint32_t)data + data_len);
if (device->qspi->refresh_method == LCD_QSPI_REFRESH_BY_LINE) {
for (uint16_t i = 0; i < device->qspi->refresh_config.vsw; i++) {
bk_lcd_qspi_send_cmd(qspi_id, device->qspi->reg_write_cmd, device->qspi->refresh_config.vsync_cmd, NULL, 0);
delay_us(40);
}
for (uint16_t i = 0; i < device->qspi->refresh_config.hfp; i++) {
bk_lcd_qspi_send_cmd(qspi_id, device->qspi->reg_write_cmd, device->qspi->refresh_config.hsync_cmd, NULL, 0);
delay_us(40);
}
qspi_hal_clear_lcd_head(&s_lcd_qspi[qspi_id].hal, 1);
qspi_hal_clear_lcd_head(&s_lcd_qspi[qspi_id].hal, 0);
bk_lcd_qspi_quad_write_start(qspi_id, device->qspi->pixel_write_config, 0);
bk_dma_start(lcd_qspi_dma_id);
ret = rtos_get_semaphore(&lcd_qspi_semaphore, 3000);
if (ret != kNoErr) {
LCD_QSPI_LOGE("ret = %d, lcd qspi get semaphore failed!\r\n", ret);
return BK_FAIL;
}
delay_us(5);
bk_lcd_qspi_quad_write_stop(qspi_id);
for (uint16_t i = 0; i < device->qspi->refresh_config.hbp; i++) {
bk_lcd_qspi_send_cmd(qspi_id, device->qspi->reg_write_cmd, device->qspi->refresh_config.hsync_cmd, NULL, 0);
delay_us(40);
}
} else if (device->qspi->refresh_method == LCD_QSPI_REFRESH_BY_FRAME) {
lcd_qspi_disp_area_config_for_frame_refresh(qspi_id, device);
bk_lcd_qspi_quad_write_start(qspi_id, device->qspi->pixel_write_config, 0);
bk_dma_start(lcd_qspi_dma_id);
ret = rtos_get_semaphore(&lcd_qspi_semaphore, 3000);
if (ret != kNoErr) {
LCD_QSPI_LOGE("ret = %d, lcd qspi get semaphore failed!\r\n", ret);
return BK_FAIL;
}
delay_us(5);
bk_lcd_qspi_quad_write_stop(qspi_id);
} else {
LCD_QSPI_LOGE("invalid lcd qspi refresh method\r\n");
return BK_FAIL;
}
#endif
return BK_OK;
}
uint8_t g_lcd_qspi_open_flag = 0;
void bk_lcd_qspi_disp_open(qspi_id_t qspi_id, const lcd_device_t *device)
{
if(g_lcd_qspi_open_flag) {
LCD_QSPI_LOGI("[%s] have opened\r\n", __FUNCTION__);
return;
}
bk_lcd_qspi_init(qspi_id, device);
g_lcd_qspi_open_flag = 1;
LCD_QSPI_LOGI("[%s] open success, frame_len:%d\r\n", __FUNCTION__, device->qspi->frame_len);
}
void bk_lcd_qspi_disp_close(qspi_id_t qspi_id)
{
g_lcd_qspi_open_flag = 0;
bk_lcd_qspi_deinit(qspi_id);
LCD_QSPI_LOGI("[%s] close success\r\n", __FUNCTION__);
}