blob: 97ce90885b5443d0e6a0d6adcf4fb64f28c1e397 [file] [log] [blame]
/*
* Copyright 2017-2018 NXP
*
* SPDX-License-Identifier: GPL-2.0+
*/
#include <common.h>
#include <dm.h>
#include <asm/io.h>
#include <linux/errno.h>
#include <asm/arch/clock.h>
#include <asm/arch/imx-regs.h>
#include <asm/arch/sci/sci.h>
#include <i2c.h>
#include <asm/arch/sys_proto.h>
#include <imxdpuv1.h>
#include <imxdpuv1_registers.h>
#include <imxdpuv1_events.h>
#include <asm/arch/imx8_lvds.h>
#include <video_fb.h>
#include <asm/arch/imx8_mipi_dsi.h>
#include <asm/arch/video_common.h>
#include <power-domain.h>
DECLARE_GLOBAL_DATA_PTR;
static struct imxdpuv1_videomode gmode;
static int8_t gdisp, gdc;
static uint32_t gpixfmt;
static GraphicDevice panel;
static int hdmi_i2c_reg_write(struct udevice *dev, uint addr, uint mask, uint data)
{
uint8_t valb;
int err;
if (mask != 0xff) {
err = dm_i2c_read(dev, addr, &valb, 1);
if (err)
return err;
valb &= ~mask;
valb |= data;
} else {
valb = data;
}
err = dm_i2c_write(dev, addr, &valb, 1);
return err;
}
static int hdmi_i2c_reg_read(struct udevice *dev, uint8_t addr, uint8_t *data)
{
uint8_t valb;
int err;
err = dm_i2c_read(dev, addr, &valb, 1);
if (err)
return err;
*data = (int)valb;
return 0;
}
/* On 8QXP ARM2, the LVDS1 signals are connected to LVDS2HDMI card's LVDS2 channel,
* LVDS0 signals are connected to LVDS2HDMI card's LVDS4 channel.
* There totally 6 channels on the cards, from 0-5.
*/
int lvds2hdmi_setup(int i2c_bus)
{
struct udevice *bus, *dev;
uint8_t chip = 0x4c;
uint8_t data;
int ret;
ret = uclass_get_device_by_seq(UCLASS_I2C, i2c_bus, &bus);
if (ret) {
printf("%s: No bus %d\n", __func__, i2c_bus);
return ret;
}
ret = dm_i2c_probe(bus, chip, 0, &dev);
if (ret) {
printf("%s: Can't find device id=0x%x, on bus %d\n",
__func__, chip, i2c_bus);
return ret;
}
/* InitIT626X(): start */
hdmi_i2c_reg_write(dev, 0x04, 0xff, 0x3d);
hdmi_i2c_reg_write(dev, 0x0f, 0xff, 0x00);
hdmi_i2c_reg_write(dev, 0x05, 0xff, 0x40);
hdmi_i2c_reg_write(dev, 0x04, 0xff, 0x15);
hdmi_i2c_reg_write(dev, 0x0f, 0xff, 0x00);
hdmi_i2c_reg_write(dev, 0x1d, 0xff, 0x66);
hdmi_i2c_reg_write(dev, 0x1e, 0xff, 0x01);
hdmi_i2c_reg_write(dev, 0x61, 0xff, 0x30);
hdmi_i2c_reg_read(dev, 0xf3, &data); /* -> 0x00 */
hdmi_i2c_reg_write(dev, 0xf3, 0xff, data & ~0x30);
hdmi_i2c_reg_read(dev, 0xf3, &data); /* -> 0x00 */
hdmi_i2c_reg_write(dev, 0xf3, 0xff, data | 0x20);
hdmi_i2c_reg_write(dev, 0x09, 0xff, 0x30);
hdmi_i2c_reg_write(dev, 0x0a, 0xff, 0xf8);
hdmi_i2c_reg_write(dev, 0x0b, 0xff, 0x37);
hdmi_i2c_reg_write(dev, 0x0f, 0xff, 0x00);
hdmi_i2c_reg_write(dev, 0xc9, 0xff, 0x00);
hdmi_i2c_reg_write(dev, 0xca, 0xff, 0x00);
hdmi_i2c_reg_write(dev, 0xcb, 0xff, 0x00);
hdmi_i2c_reg_write(dev, 0xcc, 0xff, 0x00);
hdmi_i2c_reg_write(dev, 0xcd, 0xff, 0x00);
hdmi_i2c_reg_write(dev, 0xce, 0xff, 0x00);
hdmi_i2c_reg_write(dev, 0xcf, 0xff, 0x00);
hdmi_i2c_reg_write(dev, 0xd0, 0xff, 0x00);
hdmi_i2c_reg_write(dev, 0x0f, 0xff, 0x01);
hdmi_i2c_reg_read(dev, 0x58, &data); /* -> 0x00 */
hdmi_i2c_reg_write(dev, 0x58, 0xff, data & ~(3 << 5));
hdmi_i2c_reg_write(dev, 0x0f, 0xff, 0x00);
hdmi_i2c_reg_write(dev, 0xe1, 0xff, 0x00);
hdmi_i2c_reg_write(dev, 0x0c, 0xff, 0xff);
hdmi_i2c_reg_write(dev, 0x0d, 0xff, 0xff);
hdmi_i2c_reg_read(dev, 0x0e, &data); /* -> 0x00 */
hdmi_i2c_reg_write(dev, 0x0e, 0xff, (data | 0x3));
hdmi_i2c_reg_write(dev, 0x0e, 0xff, (data & 0xfe));
hdmi_i2c_reg_write(dev, 0x0f, 0xff, 0x01);
hdmi_i2c_reg_write(dev, 0x33, 0xff, 0x00);
hdmi_i2c_reg_write(dev, 0x34, 0xff, 0x18);
hdmi_i2c_reg_write(dev, 0x35, 0xff, 0x00);
hdmi_i2c_reg_write(dev, 0x0f, 0xff, 0x00);
hdmi_i2c_reg_write(dev, 0xc4, 0xff, 0xfe);
hdmi_i2c_reg_read(dev, 0xc5, &data); /* -> 0x00 */
hdmi_i2c_reg_write(dev, 0xc5, 0xff, data | 0x30);
/* InitIT626X end */
hdmi_i2c_reg_write(dev, 0x0f, 0xff, 0x00);
hdmi_i2c_reg_write(dev, 0x04, 0xff, 0x3d);
hdmi_i2c_reg_write(dev, 0x04, 0xff, 0x15);
hdmi_i2c_reg_write(dev, 0x0f, 0xff, 0x00);
hdmi_i2c_reg_write(dev, 0x1d, 0xff, 0x66);
hdmi_i2c_reg_write(dev, 0x1e, 0xff, 0x01);
hdmi_i2c_reg_read(dev, 0xc1, &data); /* -> 0x00 */
hdmi_i2c_reg_write(dev, 0x61, 0xff, 0x10);
/* SetupAFE(): */
hdmi_i2c_reg_write(dev, 0x62, 0xff, 0x88);
hdmi_i2c_reg_write(dev, 0x63, 0xff, 0x10);
hdmi_i2c_reg_write(dev, 0x64, 0xff, 0x84);
/* SetupAFE(): end */
hdmi_i2c_reg_read(dev, 0x04, &data); /* -> 0x00 */
hdmi_i2c_reg_write(dev, 0x04, 0xff, 0x1d);
hdmi_i2c_reg_read(dev, 0x04, &data); /* -> 0x00 */
hdmi_i2c_reg_write(dev, 0x04, 0xff, 0x15);
hdmi_i2c_reg_read(dev, 0x0e, &data); /* -> 0x00 */
/* Wait video stable */
hdmi_i2c_reg_read(dev, 0x0e, &data); /* -> 0x00 */
/* Reset Video */
hdmi_i2c_reg_read(dev, 0x0d, &data); /* -> 0x00 */
hdmi_i2c_reg_write(dev, 0x0d, 0xff, 0x40);
hdmi_i2c_reg_read(dev, 0x0e, &data); /* -> 0x00 */
hdmi_i2c_reg_write(dev, 0x0e, 0xff, 0x7d);
hdmi_i2c_reg_write(dev, 0x0e, 0xff, 0x7c);
hdmi_i2c_reg_write(dev, 0x0f, 0xff, 0x00);
hdmi_i2c_reg_write(dev, 0x61, 0xff, 0x00);
hdmi_i2c_reg_read(dev, 0x61, &data); /* -> 0x00 */
hdmi_i2c_reg_read(dev, 0x62, &data); /* -> 0x00 */
hdmi_i2c_reg_read(dev, 0x63, &data); /* -> 0x00 */
hdmi_i2c_reg_read(dev, 0x64, &data); /* -> 0x00 */
hdmi_i2c_reg_read(dev, 0x65, &data); /* -> 0x00 */
hdmi_i2c_reg_read(dev, 0x66, &data); /* -> 0x00 */
hdmi_i2c_reg_read(dev, 0x67, &data); /* -> 0x00 */
hdmi_i2c_reg_write(dev, 0x0f, 0xff, 0x00);
hdmi_i2c_reg_read(dev, 0xc1, &data); /* -> 0x00 */
hdmi_i2c_reg_write(dev, 0xc1, 0xff, 0x00);
hdmi_i2c_reg_write(dev, 0xc6, 0xff, 0x03);
/* Clear AV mute */
return 0;
}
int lvds_soc_setup(int lvds_id, sc_pm_clock_rate_t pixel_clock)
{
sc_err_t err;
sc_rsrc_t lvds_rsrc, mipi_rsrc;
const char *pd_name;
struct power_domain pd;
int ret;
if (lvds_id == 0) {
lvds_rsrc = SC_R_LVDS_0;
mipi_rsrc = SC_R_MIPI_0;
pd_name = "lvds0_power_domain";
} else {
lvds_rsrc = SC_R_LVDS_1;
mipi_rsrc = SC_R_MIPI_1;
pd_name = "lvds1_power_domain";
}
/* Power up LVDS */
if (!power_domain_lookup_name(pd_name, &pd)) {
ret = power_domain_on(&pd);
if (ret) {
printf("%s Power up failed! (error = %d)\n", pd_name, ret);
return -EIO;
}
} else {
printf("%s lookup failed!\n", pd_name);
return -EIO;
}
/* Setup clocks */
err = sc_pm_set_clock_rate(-1, lvds_rsrc, SC_PM_CLK_BYPASS, &pixel_clock);
if (err != SC_ERR_NONE) {
printf("LVDS set rate SC_PM_CLK_BYPASS failed! (error = %d)\n", err);
return -EIO;
}
err = sc_pm_set_clock_rate(-1, lvds_rsrc, SC_PM_CLK_PER, &pixel_clock);
if (err != SC_ERR_NONE) {
printf("LVDS set rate SC_PM_CLK_BYPASS failed! (error = %d)\n", err);
return -EIO;
}
err = sc_pm_set_clock_rate(-1, lvds_rsrc, SC_PM_CLK_PHY, &pixel_clock);
if (err != SC_ERR_NONE) {
printf("LVDS set rate SC_PM_CLK_BYPASS failed! (error = %d)\n", err);
return -EIO;
}
if (is_imx8qxp()) {
/* For QXP, there is only one DC, and two pixel links to each LVDS with a mux provided.
* We connect LVDS0 to pixel link 0, lVDS1 to pixel link 1 from DC
*/
/* Configure to LVDS mode not MIPI DSI */
err = sc_misc_set_control(-1, mipi_rsrc, SC_C_MODE, 1);
if (err != SC_ERR_NONE) {
printf("LVDS sc_misc_set_control SC_C_MODE failed! (error = %d)\n", err);
return -EIO;
}
/* Configure to LVDS mode with single channel */
err = sc_misc_set_control(-1, mipi_rsrc, SC_C_DUAL_MODE, 0);
if (err != SC_ERR_NONE) {
printf("LVDS sc_misc_set_control SC_C_DUAL_MODE failed! (error = %d)\n", err);
return -EIO;
}
err = sc_misc_set_control(-1, mipi_rsrc, SC_C_PXL_LINK_SEL, lvds_id);
if (err != SC_ERR_NONE) {
printf("LVDS sc_misc_set_control SC_C_PXL_LINK_SEL failed! (error = %d)\n", err);
return -EIO;
}
}
err = sc_pm_clock_enable(-1, lvds_rsrc, SC_PM_CLK_BYPASS, true, false);
if (err != SC_ERR_NONE) {
printf("LVDS enable clock SC_PM_CLK_BYPASS failed! (error = %d)\n", err);
return -EIO;
}
err = sc_pm_clock_enable(-1, lvds_rsrc, SC_PM_CLK_PER, true, false);
if (err != SC_ERR_NONE) {
printf("LVDS enable clock SC_PM_CLK_PER failed! (error = %d)\n", err);
return -EIO;
}
err = sc_pm_clock_enable(-1, lvds_rsrc, SC_PM_CLK_PHY, true, false);
if (err != SC_ERR_NONE) {
printf("LVDS enable clock SC_PM_CLK_PHY failed! (error = %d)\n", err);
return -EIO;
}
return 0;
}
void lvds_configure(int lvds_id)
{
void __iomem *lvds_base;
void __iomem *mipi_base;
uint32_t phy_setting;
uint32_t mode;
if (lvds_id == 0) {
lvds_base = (void __iomem *)LVDS0_PHYCTRL_BASE;
mipi_base = (void __iomem *)MIPI0_SS_BASE;
} else {
lvds_base = (void __iomem *)LVDS1_PHYCTRL_BASE;
mipi_base = (void __iomem *)MIPI1_SS_BASE;
}
if (is_imx8qm()) {
mode =
IMX_LVDS_SET_FIELD(LVDS_CTRL_CH0_MODE, LVDS_CTRL_CH0_MODE__DI0) |
IMX_LVDS_SET_FIELD(LVDS_CTRL_CH0_DATA_WIDTH, LVDS_CTRL_CH0_DATA_WIDTH__24BIT) |
IMX_LVDS_SET_FIELD(LVDS_CTRL_CH0_BIT_MAP, LVDS_CTRL_CH0_BIT_MAP__JEIDA) |
IMX_LVDS_SET_FIELD(LVDS_CTRL_CH0_10BIT_ENABLE, LVDS_CTRL_CH0_10BIT_ENABLE__10BIT) |
IMX_LVDS_SET_FIELD(LVDS_CTRL_DI0_DATA_WIDTH, LVDS_CTRL_DI0_DATA_WIDTH__USE_30BIT);
writel(mode, lvds_base + LVDS_CTRL);
phy_setting =
LVDS_PHY_CTRL_RFB_MASK |
LVDS_PHY_CTRL_CH0_EN_MASK |
(0 << LVDS_PHY_CTRL_M_SHIFT) |
(0x04 << LVDS_PHY_CTRL_CCM_SHIFT) |
(0x04 << LVDS_PHY_CTRL_CA_SHIFT);
writel(phy_setting, lvds_base + LVDS_PHY_CTRL);
} else if (is_imx8qxp()) {
mode =
IMX_LVDS_SET_FIELD(LVDS_CTRL_CH0_MODE, LVDS_CTRL_CH0_MODE__DI0) |
IMX_LVDS_SET_FIELD(LVDS_CTRL_CH0_DATA_WIDTH, LVDS_CTRL_CH0_DATA_WIDTH__24BIT) |
IMX_LVDS_SET_FIELD(LVDS_CTRL_CH0_BIT_MAP, LVDS_CTRL_CH0_BIT_MAP__JEIDA);
phy_setting = 0x4 << 5 | 0x4 << 2 | 1 << 1 | 0x1;
writel(phy_setting, lvds_base + 0 /* PHY_CTRL*/);
writel(mode, lvds_base + LVDS_CTRL);
writel(0, lvds_base + MIPIv2_CSR_TX_ULPS);
writel(MIPI_CSR_PXL2DPI_24_BIT, lvds_base + MIPIv2_CSR_PXL2DPI);
/* Power up PLL in MIPI DSI PHY */
writel(0, mipi_base + MIPI_DSI_OFFSET + DPHY_PD_PLL);
writel(0, mipi_base + MIPI_DSI_OFFSET + DPHY_PD_TX);
}
}
int display_controller_setup(sc_pm_clock_rate_t pixel_clock)
{
sc_err_t err;
sc_rsrc_t dc_rsrc, pll0_rsrc, pll1_rsrc;
sc_pm_clock_rate_t pll_clk;
const char *pll1_pd_name;
int dc_id = gdc;
struct power_domain pd;
int ret;
if (dc_id == 0) {
dc_rsrc = SC_R_DC_0;
pll0_rsrc = SC_R_DC_0_PLL_0;
pll1_rsrc = SC_R_DC_0_PLL_1;
pll1_pd_name = "dc0_pll1";
} else {
dc_rsrc = SC_R_DC_1;
pll0_rsrc = SC_R_DC_1_PLL_0;
pll1_rsrc = SC_R_DC_1_PLL_1;
pll1_pd_name = "dc1_pll1";
}
if (!power_domain_lookup_name(pll1_pd_name, &pd)) {
ret = power_domain_on(&pd);
if (ret) {
printf("%s Power up failed! (error = %d)\n", pll1_pd_name, ret);
return -EIO;
}
} else {
printf("%s lookup failed!\n", pll1_pd_name);
return -EIO;
}
/* Setup the pll1/2 and DISP0/1 clock */
if (pixel_clock >= 40000000)
pll_clk = 1188000000;
else
pll_clk = 675000000;
err = sc_pm_set_clock_rate(-1, pll0_rsrc, SC_PM_CLK_PLL, &pll_clk);
if (err != SC_ERR_NONE) {
printf("PLL0 set clock rate failed! (error = %d)\n", err);
return -EIO;
}
err = sc_pm_set_clock_rate(-1, pll1_rsrc, SC_PM_CLK_PLL, &pll_clk);
if (err != SC_ERR_NONE) {
printf("PLL1 set clock rate failed! (error = %d)\n", err);
return -EIO;
}
err = sc_pm_set_clock_rate(-1, dc_rsrc, SC_PM_CLK_MISC0, &pixel_clock);
if (err != SC_ERR_NONE) {
printf("DISP0 set clock rate failed! (error = %d)\n", err);
return -EIO;
}
err = sc_pm_set_clock_rate(-1, dc_rsrc, SC_PM_CLK_MISC1, &pixel_clock);
if (err != SC_ERR_NONE) {
printf("DISP1 set clock rate failed! (error = %d)\n", err);
return -EIO;
}
err = sc_pm_clock_enable(-1, pll0_rsrc, SC_PM_CLK_PLL, true, false);
if (err != SC_ERR_NONE) {
printf("PLL0 clock enable failed! (error = %d)\n", err);
return -EIO;
}
err = sc_pm_clock_enable(-1, pll1_rsrc, SC_PM_CLK_PLL, true, false);
if (err != SC_ERR_NONE) {
printf("PLL1 clock enable failed! (error = %d)\n", err);
return -EIO;
}
err = sc_pm_clock_enable(-1, dc_rsrc, SC_PM_CLK_MISC0, true, false);
if (err != SC_ERR_NONE) {
printf("DISP0 clock enable failed! (error = %d)\n", err);
return -EIO;
}
err = sc_pm_clock_enable(-1, dc_rsrc, SC_PM_CLK_MISC1, true, false);
if (err != SC_ERR_NONE) {
printf("DISP1 clock enable failed! (error = %d)\n", err);
return -EIO;
}
err = sc_misc_set_control(-1, dc_rsrc, SC_C_PXL_LINK_MST1_ADDR, 0);
if (err != SC_ERR_NONE) {
printf("DC Set control fSC_C_PXL_LINK_MST1_ADDR ailed! (error = %d)\n", err);
return -EIO;
}
err = sc_misc_set_control(-1, dc_rsrc, SC_C_PXL_LINK_MST1_ENB, 1);
if (err != SC_ERR_NONE) {
printf("DC Set control SC_C_PXL_LINK_MST1_ENB failed! (error = %d)\n", err);
return -EIO;
}
err = sc_misc_set_control(-1, dc_rsrc, SC_C_PXL_LINK_MST1_VLD, 1);
if (err != SC_ERR_NONE) {
printf("DC Set control SC_C_PXL_LINK_MST1_VLD failed! (error = %d)\n", err);
return -EIO;
}
err = sc_misc_set_control(-1, dc_rsrc, SC_C_PXL_LINK_MST2_ADDR, 0);
if (err != SC_ERR_NONE) {
printf("DC Set control SC_C_PXL_LINK_MST2_ADDR ailed! (error = %d)\n", err);
return -EIO;
}
err = sc_misc_set_control(-1, dc_rsrc, SC_C_PXL_LINK_MST2_ENB, 1);
if (err != SC_ERR_NONE) {
printf("DC Set control SC_C_PXL_LINK_MST2_ENB failed! (error = %d)\n", err);
return -EIO;
}
err = sc_misc_set_control(-1, dc_rsrc, SC_C_PXL_LINK_MST2_VLD, 1);
if (err != SC_ERR_NONE) {
printf("DC Set control SC_C_PXL_LINK_MST2_VLD failed! (error = %d)\n", err);
return -EIO;
}
err = sc_misc_set_control(-1, dc_rsrc, SC_C_SYNC_CTRL0, 1);
if (err != SC_ERR_NONE) {
printf("DC Set control SC_C_SYNC_CTRL0 failed! (error = %d)\n", err);
return -EIO;
}
err = sc_misc_set_control(-1, dc_rsrc, SC_C_SYNC_CTRL1, 1);
if (err != SC_ERR_NONE) {
printf("DC Set control SC_C_SYNC_CTRL1 failed! (error = %d)\n", err);
return -EIO;
}
return 0;
}
void *video_hw_init(void)
{
imxdpuv1_channel_params_t channel;
imxdpuv1_layer_t layer;
void *fb;
int8_t imxdpuv1_id = gdc;
if (imxdpuv1_id != 0 || (imxdpuv1_id == 1 && !is_imx8qm())) {
printf("%s(): invalid imxdpuv1_id %d", __func__, imxdpuv1_id);
return NULL;
}
panel.winSizeX = gmode.hlen;
panel.winSizeY = gmode.vlen;
panel.plnSizeX = gmode.hlen;
panel.plnSizeY = gmode.vlen;
panel.gdfBytesPP = 4;
panel.gdfIndex = GDF_32BIT_X888RGB;
panel.memSize = gmode.hlen * gmode.vlen * panel.gdfBytesPP;
/* Allocate framebuffer */
fb = memalign(0x1000,
roundup(panel.memSize, 0x1000));
if (!fb) {
printf("IMXDPUv1: Error allocating framebuffer!\n");
return NULL;
}
/* Wipe framebuffer */
memset(fb, 0, panel.memSize);
panel.frameAdrs = (ulong)fb;
imxdpuv1_init(imxdpuv1_id);
imxdpuv1_disp_enable_frame_gen(imxdpuv1_id, 0, IMXDPUV1_FALSE);
imxdpuv1_disp_enable_frame_gen(imxdpuv1_id, 1, IMXDPUV1_FALSE);
imxdpuv1_disp_setup_frame_gen(imxdpuv1_id, gdisp,
(const struct imxdpuv1_videomode *)&gmode,
0x3ff, 0, 0, 1, IMXDPUV1_DISABLE);
imxdpuv1_disp_init(imxdpuv1_id, gdisp);
imxdpuv1_disp_setup_constframe(imxdpuv1_id,
gdisp, 0, 0, 0xff, 0); /* blue */
if (gdisp == 0)
channel.common.chan = IMXDPUV1_CHAN_VIDEO_0;
else
channel.common.chan = IMXDPUV1_CHAN_VIDEO_1;
channel.common.src_pixel_fmt = gpixfmt;
channel.common.dest_pixel_fmt = gpixfmt;
channel.common.src_width = gmode.hlen;
channel.common.src_height = gmode.vlen;
channel.common.clip_width = 0;
channel.common.clip_height = 0;
channel.common.clip_top = 0;
channel.common.clip_left = 0;
channel.common.dest_width = gmode.hlen;
channel.common.dest_height = gmode.vlen;
channel.common.dest_top = 0;
channel.common.dest_left = 0;
channel.common.stride =
gmode.hlen * imxdpuv1_bytes_per_pixel(IMXDPUV1_PIX_FMT_BGRA32);
channel.common.disp_id = gdisp;
channel.common.const_color = 0;
channel.common.use_global_alpha = 0;
channel.common.use_local_alpha = 0;
imxdpuv1_init_channel(imxdpuv1_id, &channel);
imxdpuv1_init_channel_buffer(imxdpuv1_id,
channel.common.chan,
gmode.hlen * imxdpuv1_bytes_per_pixel(IMXDPUV1_PIX_FMT_RGB32),
IMXDPUV1_ROTATE_NONE,
(dma_addr_t)fb,
0,
0);
layer.enable = IMXDPUV1_TRUE;
layer.secondary = get_channel_blk(channel.common.chan);
if (gdisp == 0) {
layer.stream = IMXDPUV1_DISPLAY_STREAM_0;
layer.primary = IMXDPUV1_ID_CONSTFRAME0;
} else {
layer.stream = IMXDPUV1_DISPLAY_STREAM_1;
layer.primary = IMXDPUV1_ID_CONSTFRAME1;
}
imxdpuv1_disp_setup_layer(
imxdpuv1_id, &layer, IMXDPUV1_LAYER_0, 1);
imxdpuv1_disp_set_layer_global_alpha(
imxdpuv1_id, IMXDPUV1_LAYER_0, 0xff);
imxdpuv1_disp_set_layer_position(
imxdpuv1_id, IMXDPUV1_LAYER_0, 0, 0);
imxdpuv1_disp_set_chan_position(
imxdpuv1_id, channel.common.chan, 0, 0);
imxdpuv1_disp_enable_frame_gen(imxdpuv1_id, gdisp, IMXDPUV1_ENABLE);
debug("IMXDPU display start ...\n");
return &panel;
}
void imxdpuv1_fb_disable(void)
{
/* Disable video only when video init is done */
if (panel.frameAdrs)
imxdpuv1_disp_enable_frame_gen(gdc, gdisp, IMXDPUV1_DISABLE);
}
int imxdpuv1_fb_init(struct fb_videomode const *mode,
uint8_t disp, uint32_t pixfmt)
{
if (disp > 1) {
printf("Invalid disp parameter %d for imxdpuv1_fb_init\n", disp);
return -EINVAL;
}
memset(&gmode, 0, sizeof(struct imxdpuv1_videomode));
gmode.pixelclock = PS2KHZ(mode->pixclock) * 1000;
gmode.hlen = mode->xres;
gmode.hbp = mode->left_margin;
gmode.hfp = mode->right_margin;
gmode.vlen = mode->yres;
gmode.vbp = mode->upper_margin;
gmode.vfp = mode->lower_margin;
gmode.hsync = mode->hsync_len;
gmode.vsync = mode->vsync_len;
gmode.flags = IMXDPUV1_MODE_FLAGS_HSYNC_POL | IMXDPUV1_MODE_FLAGS_VSYNC_POL | IMXDPUV1_MODE_FLAGS_DE_POL;
if (is_imx8qm()) { /* QM has two DCs each contains one LVDS as secondary display output */
gdisp = 1;
gdc = disp;
} else if (is_imx8qxp()) { /* QXP has one DC which contains 2 LVDS/MIPI_DSI combo */
gdisp = disp;
gdc = 0;
} else {
printf("Unsupported SOC for imxdpuv1_fb_init\n");
return -EPERM;
}
gpixfmt = pixfmt;
debug("imxdpuv1_fb_init, dc=%d, disp=%d\n", gdc, gdisp);
return 0;
}