This repository has been archived on 2023-11-03. You can view files and clone it, but cannot push or open issues or pull requests.
QM_Zynq_DSI_SW/src/lcd_test.c
Yilin Sun bb2190586f
Initial commit.
Signed-off-by: Yilin Sun <imi415@imi.moe>
2023-11-03 09:36:07 +08:00

349 lines
11 KiB
C

/******************************************************************************
*
* Copyright (C) 2009 - 2014 Xilinx, Inc. All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* Use of the Software is limited solely to applications:
* (a) running on a Xilinx device, or
* (b) that interact with a Xilinx device through a bus or interconnect.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* XILINX BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
* OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
* Except as contained in this notice, the name of the Xilinx shall not be used
* in advertising or otherwise to promote the sale, use or other dealings in
* this Software without prior written authorization from Xilinx.
*
******************************************************************************/
/*
* helloworld.c: simple test application
*
* This application configures UART 16550 to baud rate 9600.
* PS7 UART (Zynq) is not initialized by this application, since
* bootrom/bsp configures it to baud rate 115200
*
* ------------------------------------------------
* | UART TYPE BAUD RATE |
* ------------------------------------------------
* uartns550 9600
* uartlite Configurable only in HW design
* ps7_uart 115200 (configured by bootrom/bsp)
*/
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#include "platform.h"
#include "xil_printf.h"
#include "xil_cache.h"
#include "xparameters.h"
#include "xv_frmbufrd.h"
#include "xscugic.h"
#include "xdsitxss.h"
#include "gpio_lp.h"
#define IMAGE_WIDTH 540
#define IMAGE_HEIGHT 960
#define IMAGE_PIXEL_SIZE 4
#define BITBANG_COMMAND 1
#define ENABLE_VIDEO 1
static uint8_t __aligned(64) s_image_buffer[IMAGE_WIDTH * IMAGE_HEIGHT * IMAGE_PIXEL_SIZE];
static XV_frmbufrd s_frmbufrd;
static XDsiTxSs s_dsi_txss;
static uint8_t s_lcd_init_seq[] = {
0xFF, 4, 0xAA, 0x55, 0x25, 0x01,
0xF0, 5, 0x55, 0xAA, 0x52, 0x08, 0x00,
0xB1, 3, 0xFC, 0x00, 0x00,
0xB8, 4, 0x01, 0x02, 0x02, 0x02,
0xBC, 3, 0x05, 0x05, 0x05,
0xB7, 2, 0x00, 0x00,
0xC8, 18, 0x01, 0x00, 0x46, 0x1E, 0x46, 0x1E, 0x46, 0x1E, 0x46, 0x1E, 0x64, 0x3C, 0x3C, 0x64, 0x64, 0x3C, 0x3C, 0x64,
0xF0, 5, 0x55, 0xAA, 0x52, 0x08, 0x01,
0xB0, 3, 0x05, 0x05, 0x05,
0xB6, 3, 0x44, 0x44, 0x44,
0xB1, 3, 0x05, 0x05, 0x05,
0xB7, 3, 0x34, 0x34, 0x34,
0xB3, 3, 0x16, 0x16, 0x16,
0xB4, 3, 0x0A, 0x0A, 0x0A,
0xBC, 3, 0x00, 0x90, 0x11,
0xBD, 3, 0x00, 0x90, 0x11,
0xBE, 1, 0x51,
0xD1, 16, 0x00, 0x17, 0x00, 0x24, 0x00, 0x3D, 0x00, 0x52, 0x00, 0x66, 0x00, 0x86, 0x00, 0xA0, 0x00, 0xCC,
0xD2, 16, 0x00, 0xF1, 0x01, 0x26, 0x01, 0x4E, 0x01, 0x8C, 0x01, 0xBC, 0x01, 0xBE, 0x01, 0xE7, 0x02, 0x0E,
0xD3, 16, 0x02, 0x22, 0x02, 0x3C, 0x02, 0x4F, 0x02, 0x71, 0x02, 0x90, 0x02, 0xC6, 0x02, 0xF1, 0x03, 0x3A,
0xD4, 4, 0x03, 0xB5, 0x03, 0xC1,
0xD5, 16, 0x00, 0x17, 0x00, 0x24, 0x00, 0x3D, 0x00, 0x52, 0x00, 0x66, 0x00, 0x86, 0x00, 0xA0, 0x00, 0xCC,
0xD6, 16, 0x00, 0xF1, 0x01, 0x26, 0x01, 0x4E, 0x01, 0x8C, 0x01, 0xBC, 0x01, 0xBE, 0x01, 0xE7, 0x02, 0x0E,
0xD7, 16, 0x02, 0x22, 0x02, 0x3C, 0x02, 0x4F, 0x02, 0x71, 0x02, 0x90, 0x02, 0xC6, 0x02, 0xF1, 0x03, 0x3A,
0xD8, 4, 0x03, 0xB5, 0x03, 0xC1,
0xD9, 16, 0x00, 0x17, 0x00, 0x24, 0x00, 0x3D, 0x00, 0x52, 0x00, 0x66, 0x00, 0x86, 0x00, 0xA0, 0x00, 0xCC,
0xDD, 16, 0x00, 0xF1, 0x01, 0x26, 0x01, 0x4E, 0x01, 0x8C, 0x01, 0xBC, 0x01, 0xBE, 0x01, 0xE7, 0x02, 0x0E,
0xDE, 16, 0x02, 0x22, 0x02, 0x3C, 0x02, 0x4F, 0x02, 0x71, 0x02, 0x90, 0x02, 0xC6, 0x02, 0xF1, 0x03, 0x3A,
0xDF, 4, 0x03, 0xB5, 0x03, 0xC1,
0xE0, 16, 0x00, 0x17, 0x00, 0x24, 0x00, 0x3D, 0x00, 0x52, 0x00, 0x66, 0x00, 0x86, 0x00, 0xA0, 0x00, 0xCC,
0xE1, 16, 0x00, 0xF1, 0x01, 0x26, 0x01, 0x4E, 0x01, 0x8C, 0x01, 0xBC, 0x01, 0xBE, 0x01, 0xE7, 0x02, 0x0E,
0xE2, 16, 0x02, 0x22, 0x02, 0x3C, 0x02, 0x4F, 0x02, 0x71, 0x02, 0x90, 0x02, 0xC6, 0x02, 0xF1, 0x03, 0x3A,
0xE3, 4, 0x03, 0xB5, 0x03, 0xC1,
0xE4, 16, 0x00, 0x17, 0x00, 0x24, 0x00, 0x3D, 0x00, 0x52, 0x00, 0x66, 0x00, 0x86, 0x00, 0xA0, 0x00, 0xCC,
0xE5, 16, 0x00, 0xF1, 0x01, 0x26, 0x01, 0x4E, 0x01, 0x8C, 0x01, 0xBC, 0x01, 0xBE, 0x01, 0xE7, 0x02, 0x0E,
0xE6, 16, 0x02, 0x22, 0x02, 0x3C, 0x02, 0x4F, 0x02, 0x71, 0x02, 0x90, 0x02, 0xC6, 0x02, 0xF1, 0x03, 0x3A,
0xE7, 4, 0x03, 0xB5, 0x03, 0xC1,
0xE8, 16, 0x00, 0x17, 0x00, 0x24, 0x00, 0x3D, 0x00, 0x52, 0x00, 0x66, 0x00, 0x86, 0x00, 0xA0, 0x00, 0xCC,
0xE9, 16, 0x00, 0xF1, 0x01, 0x26, 0x01, 0x4E, 0x01, 0x8C, 0x01, 0xBC, 0x01, 0xBE, 0x01, 0xE7, 0x02, 0x0E,
0xEA, 16, 0x02, 0x22, 0x02, 0x3C, 0x02, 0x4F, 0x02, 0x71, 0x02, 0x90, 0x02, 0xC6, 0x02, 0xF1, 0x03, 0x3A,
0xEB, 4, 0x03, 0xB5, 0x03, 0xC1,
0x35, 1, 0x00,
0x11, 0
};
static int init_drivers(void) {
XV_frmbufrd_Config *frmbufrd_config = XV_frmbufrd_LookupConfig(XPAR_VIDEO_ROUTINE_V_FRMBUF_RD_0_DEVICE_ID);
int status = XV_frmbufrd_Initialize(&s_frmbufrd, frmbufrd_config->BaseAddress);
if(status != XST_SUCCESS) {
printf("FramebufRd initialization failed.\r\n");
return XST_FAILURE;
}
return XST_SUCCESS;
}
static void config_frmbuf(void) {
XV_frmbufrd_Set_HwReg_width(&s_frmbufrd, IMAGE_WIDTH);
XV_frmbufrd_Set_HwReg_height(&s_frmbufrd, IMAGE_HEIGHT);
XV_frmbufrd_Set_HwReg_stride(&s_frmbufrd, IMAGE_WIDTH * IMAGE_PIXEL_SIZE);
XV_frmbufrd_Set_HwReg_video_format(&s_frmbufrd, 27); // BGRX8
XV_frmbufrd_Set_HwReg_frm_buffer_V(&s_frmbufrd, (u32)s_image_buffer);
XV_frmbufrd_EnableAutoRestart(&s_frmbufrd);
XV_frmbufrd_Start(&s_frmbufrd);
printf("Frame buffer read configured.\r\n");
}
#if BITBANG_COMMAND
#else
static int dsi_sendcommand(XDsiTxSs *txss, uint8_t command, uint8_t *param, uint8_t param_length) {
if(param_length > 1) {
txss->CmdPkt.CmdPkt = XDSI_CMD_MODE_LONG_PKT;
txss->CmdPkt.SpktData.DataType = 0x39; // DCS long write
txss->CmdPkt.SpktData.Data0 = param_length + 1; // word count.
txss->CmdPkt.SpktData.VcId = 0;
uint8_t *pkt_buffer = (uint8_t *)txss->CmdPkt.LongPktData;
memset(pkt_buffer, 0x00, 256);
pkt_buffer[0] = command;
memcpy(&pkt_buffer[1], param, param_length);
}
else if(param_length > 0) {
txss->CmdPkt.CmdPkt = XDSI_CMD_MODE_SHORT_PKT;
txss->CmdPkt.SpktData.DataType = 0x15; // DCS write, 1 parameter
txss->CmdPkt.SpktData.Data0 = command;
txss->CmdPkt.SpktData.Data1 = param[0];
txss->CmdPkt.SpktData.VcId = 0;
}
else {
txss->CmdPkt.CmdPkt = XDSI_CMD_MODE_SHORT_PKT;
txss->CmdPkt.SpktData.DataType = 0x05; // DCS write, no parameter
txss->CmdPkt.SpktData.Data0 = command;
txss->CmdPkt.SpktData.Data1 = 0x00;
txss->CmdPkt.SpktData.VcId = 0;
}
return XDsiTxSs_SendCmdModePacket(txss);
}
#endif
static int dsi_initseq(XDsiTxSs *txss) {
#if BITBANG_COMMAND
int status = gpio_lp_write_dcs(0x01, NULL, 0x00);
#else
int status = dsi_sendcommand(txss, 0x01, NULL, 0x00);
#endif
if(status != XST_SUCCESS) {
printf("Reset command send failed.\r\n");
return status;
}
usleep(200 * 1000);
uint32_t i = 0;
while(i < sizeof(s_lcd_init_seq)) {
#if BITBANG_COMMAND
status = gpio_lp_write_dcs(s_lcd_init_seq[i], &s_lcd_init_seq[i + 2], s_lcd_init_seq[i + 1]);
#else
status = dsi_sendcommand(txss, s_lcd_init_seq[i], &s_lcd_init_seq[i + 2], s_lcd_init_seq[i + 1]);
#endif
if(status != XST_SUCCESS) {
printf("Send initialization command failed at %ld", i);
return status;
}
i += s_lcd_init_seq[i + 1] + 2; // Next seq
}
usleep(200 * 1000);
#if BITBANG_COMMAND
status = gpio_lp_write_dcs(0x29, NULL, 0x00);
#else
status = dsi_sendcommand(txss, 0x29, NULL, 0x00);
#endif
return status;
}
static int config_dsi(void) {
XDsiTxSs_Config *config = XDsiTxSs_LookupConfig(XPAR_VIDEO_ROUTINE_MIPI_DSI_TX_SUBSYSTEM_0_DEVICE_ID);
if(!config) return XST_FAILURE;
int status = XDsiTxSs_CfgInitialize(&s_dsi_txss, config, config->BaseAddr);
if(status != XST_SUCCESS) {
printf("DSI TX subsystem initialization failed.\r\n");
return status;
}
status = XDsiTxSs_SelfTest(&s_dsi_txss);
if(status != XST_SUCCESS) {
printf("DSI TX subsystem self test failed.\r\n");
return status;
}
else {
printf("DSI TX subsystem self test succeeded.\r\n");
}
XDsiTxSs_Reset(&s_dsi_txss);
#if BITBANG_COMMAND
gpio_lp_init();
gpio_lp_setup();
gpio_lp_lcd_reset();
// Return all lanes to LP-11 state
usleep(200 * 1000);
#else
status = XDsiTxSs_SetDSIMode(&s_dsi_txss, XDSI_COMMAND_MODE);
if(status != XST_SUCCESS) {
printf("Set DSI mode failed.\r\n");
}
usleep(20 * 1000);
status = XDsiTxSs_Activate(&s_dsi_txss, XDSITXSS_PHY, XDSITXSS_ENABLE);
if(status != XST_SUCCESS) {
printf("D-PHY enable failed.\r\n");
}
status = XDsiTxSs_Activate(&s_dsi_txss, XDSITXSS_DSI, XDSITXSS_ENABLE);
if(status != XST_SUCCESS) {
printf("DSI controller enable failed.\r\n");
}
#endif
usleep(200 * 1000);
dsi_initseq(&s_dsi_txss);
#if BITBANG_COMMAND
gpio_lp_release();
#else
status = XDsiTxSs_Activate(&s_dsi_txss, XDSITXSS_DSI, XDSITXSS_DISABLE);
#endif
#if ENABLE_VIDEO
XDsiTxSs_Reset(&s_dsi_txss);
XDsi_VideoTiming timing = {
.HActive = 540 * 3,
.HFrontPorch = 83,
.HBackPorch = 360,
.HSyncWidth = 7,
.VActive = 960,
.VFrontPorch = 15,
.VBackPorch = 15,
.VSyncWidth = 10,
.BLLPBurst = 0,
};
XDsiTxSs_SetCustomVideoInterfaceTiming(&s_dsi_txss, XDSI_VM_NON_BURST_SYNC_EVENT, &timing);
status = XDsiTxSs_Activate(&s_dsi_txss, XDSITXSS_PHY, XDSITXSS_ENABLE);
if(status != XST_SUCCESS) {
printf("D-PHY enable failed.\r\n");
}
status = XDsiTxSs_Activate(&s_dsi_txss, XDSITXSS_DSI, XDSITXSS_ENABLE);
if(status != XST_SUCCESS) {
printf("DSI enable failed.\r\n");
}
s_dsi_txss.SpktData.Data0 = 0x00;
s_dsi_txss.SpktData.Data1 = 0x00;
s_dsi_txss.SpktData.DataType = 0x32;
s_dsi_txss.SpktData.VcId = 0;
XDsiTxSs_SendShortPacket(&s_dsi_txss);
#endif
return status;
}
int main()
{
init_platform();
if(init_drivers() != XST_SUCCESS) {
printf("Driver initialization failed.\r\n");
for(;;) {
//
}
}
config_frmbuf();
if(config_dsi() != XST_SUCCESS) {
printf("DSI TXSS initialization failed.\r\n");
for(;;) {
//
}
}
memset(s_image_buffer, 0xFF, IMAGE_WIDTH * IMAGE_HEIGHT * IMAGE_PIXEL_SIZE);
Xil_DCacheFlushRange((UINTPTR)s_image_buffer, IMAGE_WIDTH * IMAGE_HEIGHT * IMAGE_PIXEL_SIZE);
for(;;) {
sleep(1);
}
print("Hello World\r\n");
print("Successfully ran Hello World application\r\n");
cleanup_platform();
return 0;
}