Files
2026-09-22 09:38:26 +08:00

330 lines
8.7 KiB
C

// SPDX-License-Identifier: GPL-2.0+
/*
* MIPI CSI/DSI TX display driver
*
* hammer.hsieh <[email protected]>
*/
#include <common.h>
#include <display.h>
#include <dm.h>
#include <malloc.h>
#include <video.h>
#include <dm/uclass-internal.h>
#include <linux/io.h>
#include "display2.h"
#include "reg_disp.h"
#include "disp_dmix.h"
#include "disp_tgen.h"
#include "disp_tcon.h"
#include "disp_vpp.h"
#include "disp_osd.h"
#include "disp_mipitx.h"
#include <asm/gpio.h>
#if CONFIG_IS_ENABLED(DM_I2C) && defined(CONFIG_SP7350_LT8912B_BRIDGE)
#include "disp_i2c_lt8912b.h"
#elif CONFIG_IS_ENABLED(DM_I2C) && defined(CONFIG_SP7350_RASPBERRYPI_DSI_PANEL)
#include "disp_i2c_raspberrypi.h"
#endif
//#define debug printf
extern u32 osd0_header[];
struct sp7350_disp_priv *sp_gpio;
#if CONFIG_IS_ENABLED(DM_I2C) && defined(CONFIG_SP7350_RASPBERRYPI_DSI_PANEL)
extern int raspberrypi_check_exist(struct udevice *p1);
extern void raspberrypi_pre_init(struct udevice *p1);
extern void raspberrypi_post_init(struct udevice *p1);
#endif
#if CONFIG_IS_ENABLED(DM_I2C) && defined(CONFIG_SP7350_LT8912B_BRIDGE)
extern void lt8912_write_init_config(struct udevice *p1);
extern void lt8912_write_mipi_basic_config(struct udevice *p2);
extern void lt8912_write_param_by_resolution(struct udevice *p2, int w, int h);
extern void lt8912_write_dds_config(struct udevice *p2);
extern void lt8912_write_rxlogicres_config(struct udevice *p1);
extern void lt8912_write_lvds_config(struct udevice *p2);
extern void lt8912_hdmi_mode_setup(struct udevice *p1, int hdmi_dvi_sel);
extern void lt8912_audio_setup(struct udevice *p1, struct udevice *p3, int w, int h);
#endif
DECLARE_GLOBAL_DATA_PTR;
static int sp7350_display_probe(struct udevice *dev)
{
struct video_uc_plat *uc_plat = dev_get_uclass_plat(dev);
struct video_priv *uc_priv = dev_get_uclass_priv(dev);
int max_bpp = 8; //default 8BPP format
int is_mipi_dsi_tx = 1; //default MIPI_DSI_TX out
int width, height;
void *fb_alloc;
u32 osd_base_addr;
#if CONFIG_IS_ENABLED(DM_I2C) && defined(CONFIG_SP7350_LT8912B_BRIDGE)
int i;
unsigned int lt8912b_hdmi_dvi_sel = 0;
#elif CONFIG_IS_ENABLED(DM_I2C) && defined(CONFIG_SP7350_RASPBERRYPI_DSI_PANEL)
int i;
#endif
struct sp7350_disp_priv *priv = dev_get_priv(dev);
int ret;
width = CONFIG_VIDEO_SP7350_MAX_XRES;
height = CONFIG_VIDEO_SP7350_MAX_YRES;
printf("Disp: probe ... \n");
DISP_MOON2_REG->sft_cfg[3] = 0xffffffff; //enable all disp clken
printf("Disp: init %dx%d settings\n", width, height);
#if CONFIG_IS_ENABLED(DM_I2C) && defined(CONFIG_SP7350_LT8912B_BRIDGE)
if ((CONFIG_VIDEO_SP7350_MAX_XRES == 480) && (CONFIG_VIDEO_SP7350_MAX_YRES == 272)){
width = 720;
height = 480;
}
#endif
#if 0
/*
* refer to kernel dts reserved-memory disp_reserve
*/
fb_alloc = (void *)0x5c000000;
#else
/*
* alloc memory in uboot
*/
fb_alloc = malloc((width*height*
(CONFIG_VIDEO_SP7350_MAX_BPP >> 3)) + 64 );
#endif
//printf("Disp: fb_alloc = 0x%p\n", fb_alloc);
//printf("Disp: fb_alloc = %ld\n", sizeof(fb_alloc));
if (fb_alloc == NULL) {
printf("Error: malloc in %s failed! \n",__func__);
return -EINVAL;
}
if(((uintptr_t)fb_alloc & 0xffffffff00000000) != 0) {
printf("Error: malloc addr over 4GB(%s)\n",__func__);
return -EINVAL;
}
if(((uintptr_t)fb_alloc & 0x3f) != 0)
fb_alloc = (void *)(((uintptr_t)fb_alloc + 64 ) & ~0x3f);
DRV_DMIX_Init();
DRV_TGEN_Init(width, height);
DRV_TCON_Init(width, height);
DRV_VPP_Init(width, height);
DRV_OSD_Init(width, height);
#if CONFIG_IS_ENABLED(DM_I2C) && defined(CONFIG_SP7350_LT8912B_BRIDGE)
lt8912b_hdmi_dvi_sel = dev_read_u32_default(dev,"sunplus,lt8912b_hdmi_mode", 0);
//printf("Disp: sunplus,lt8912b_hdmi_mode %d \n", lt8912b_hdmi_dvi_sel);
#elif CONFIG_IS_ENABLED(DM_I2C) && defined(CONFIG_SP7350_RASPBERRYPI_DSI_PANEL)
#else
if (is_mipi_dsi_tx) {
ret = gpio_request_by_name(dev, "reset-gpios", 0, &priv->reset, GPIOD_IS_OUT);
if (ret) {
printf("reset-gpios not found\n");
if (ret != -ENOENT)
return ret;
}
}
#endif
sp_gpio = priv;
#if CONFIG_IS_ENABLED(DM_I2C) && defined(CONFIG_SP7350_LT8912B_BRIDGE)
DRV_mipitx_Init_1(is_mipi_dsi_tx, width, height);
#else
DRV_mipitx_Init(is_mipi_dsi_tx, width, height);
#endif
//osd_base_addr = (u32)((uintptr_t)fb_alloc & 0x00000000ffffffff);
osd_base_addr = (u32)((uintptr_t)fb_alloc);
if(CONFIG_VIDEO_SP7350_MAX_BPP == 8) {
API_OSD_UI_Init(width ,height, osd_base_addr, DRV_OSD_REGION_FORMAT_8BPP);
max_bpp = 8;
}
else if(CONFIG_VIDEO_SP7350_MAX_BPP == 16) {
API_OSD_UI_Init(width ,height, osd_base_addr, DRV_OSD_REGION_FORMAT_RGB_565);
max_bpp = 16;
}
else if(CONFIG_VIDEO_SP7350_MAX_BPP == 32) {
API_OSD_UI_Init(width ,height, osd_base_addr, DRV_OSD_REGION_FORMAT_ARGB_8888);
max_bpp = 32;
}
else {
//printf("only support 8/16/32\n",);
API_OSD_UI_Init(width ,height, osd_base_addr, DRV_OSD_REGION_FORMAT_8BPP);
max_bpp = 8;
}
//printf("G189.02 0x%08x\n", G189_OSD0_REG->osd_base_addr);
#if CONFIG_IS_ENABLED(DM_I2C) && defined(CONFIG_SP7350_LT8912B_BRIDGE)
if ((CONFIG_VIDEO_SP7350_MAX_XRES == 480) && (CONFIG_VIDEO_SP7350_MAX_YRES == 272)){
width = 480;
height = 272;
}
#endif
uc_plat->base = (ulong)fb_alloc;
uc_plat->size = width * height * (max_bpp >> 3);
uc_priv->xsize = width;
uc_priv->ysize = height;
uc_priv->rot = CONFIG_VIDEO_SP7350_ROTATE;
if(CONFIG_VIDEO_SP7350_MAX_BPP == 16) {
uc_priv->bpix = VIDEO_BPP16;
uc_priv->format = VIDEO_FMT_RGB565;
}
else if(CONFIG_VIDEO_SP7350_MAX_BPP == 32) {
uc_priv->bpix = VIDEO_BPP32;
uc_priv->format = VIDEO_FMT_ARGB8888;
}
else {
uc_priv->bpix = VIDEO_BPP8;
uc_priv->format = VIDEO_FMT_8BPP_ARGB;
}
#ifdef CONFIG_BMP_8BPP_UPDATE_CMAP
if(uc_priv->bpix == VIDEO_BPP8) {
uc_priv->cmap = (u32 *)(uintptr_t)(osd0_header+32);
}
#endif
#if CONFIG_IS_ENABLED(DM_I2C) && defined(CONFIG_SP7350_RASPBERRYPI_DSI_PANEL)
for (i = 0; i < 8; i++) {
ret = i2c_get_chip_for_busnum(i, ATMEL_MCU_I2C_ADDR, 1, &priv->chip1);
//printf("i2c bus%d chip1 scan ret %d\n", i, ret);
if (ret) {
//printf("i2c bus%d chip1 scan ret %d\n", i, ret);
if (i == 7) {
printf("Disp: dsi panel not found\n");
goto skip_attiny88;
}
} else {
break;
}
}
ret = raspberrypi_check_exist(priv->chip1);
//if (ret)
// goto skip_attiny88;
raspberrypi_pre_init(priv->chip1);
DRV_mipitx_Init(is_mipi_dsi_tx, width, height);
raspberrypi_post_init(priv->chip1);
printf("Disp: init dsi panel RASPBERRYPI_DSI_PANEL\n");
//printf("MIPITX DSI Panel : RASPBERRYPI_DSI_PANEL(%dx%d)\n", width, height);
skip_attiny88:
#endif
#if CONFIG_IS_ENABLED(DM_I2C) && defined(CONFIG_SP7350_LT8912B_BRIDGE)
for (i = 0; i < 8; i++) {
ret = i2c_get_chip_for_busnum(i, LT8912B_I2C_ADDR_MAIN, 1, &priv->chip1);
if (ret) {
//printf("i2c bus%d chip1 scan ret %d\n", i, ret);
if (i == 7) {
printf("Disp: lt8912b bridge not found\n");
goto skip_lt8912b;
} else {
continue;
}
}
ret = i2c_get_chip_for_busnum(i, LT8912B_I2C_ADDR_CEC_DSI, 1, &priv->chip2);
if (ret) {
//printf("i2c bus%d chip2 scan ret %d\n", i, ret);
return ret;
} else {
;//break;
}
ret = i2c_get_chip_for_busnum(i, LT8912B_I2C_ADDR_HDMITX_DSI, 1, &priv->chip3);
if (ret) {
//printf("i2c bus%d chip3 scan ret %d\n", i, ret);
return ret;
} else {
break;
}
}
if ((CONFIG_VIDEO_SP7350_MAX_XRES == 480) && (CONFIG_VIDEO_SP7350_MAX_YRES == 272)){
lt8912b_hdmi_dvi_sel = 0; //dvi mode only
width = 720;
height = 480;
}
if (lt8912b_hdmi_dvi_sel)
printf("Disp:: init lt8912b bridge ic\n");
else
printf("Disp: init lt8912b bridge ic\n");
lt8912_write_init_config(priv->chip1);
lt8912_write_mipi_basic_config(priv->chip2);
lt8912_write_param_by_resolution(priv->chip2, width, height);
lt8912_write_dds_config(priv->chip2);
lt8912_write_rxlogicres_config(priv->chip1);
lt8912_write_lvds_config(priv->chip2);
if (lt8912b_hdmi_dvi_sel)
lt8912_hdmi_mode_setup(priv->chip1, 1); //0: DVI Mode, (1: HDMI Mode)
else
lt8912_hdmi_mode_setup(priv->chip1, 0); //(0: DVI Mode), 1: HDMI Mode
lt8912_audio_setup(priv->chip1, priv->chip3, width, height);
skip_lt8912b:
#endif
video_set_flush_dcache(dev, true);
printf("Disp: probe done \n");
return 0;
}
static int sp7350_display_bind(struct udevice *dev)
{
struct video_uc_plat *uc_plat = dev_get_uclass_plat(dev);
uc_plat->size = 0;
return 0;
}
static const struct video_ops sp7350_display_ops = {
};
static const struct udevice_id sp7350_display_ids[] = {
{ .compatible = "sunplus,sp7350-display" },
{ .compatible = "sunplus,sp7350-display-subsystem" },
{ }
};
U_BOOT_DRIVER(sp7350_display) = {
.name = "sp7350_display",
.id = UCLASS_VIDEO,
.ops = &sp7350_display_ops,
.of_match = sp7350_display_ids,
.bind = sp7350_display_bind,
.probe = sp7350_display_probe,
.priv_auto = sizeof(struct sp7350_disp_priv),
};