/* SPDX-License-Identifier: GPL-2.0-only */ #include <arch/mmu.h> #include <device/mmio.h> #include <console/console.h> #include <device/device.h> #include <delay.h> #include <edid.h> #include <gpio.h> #include <stdint.h> #include <soc/addressmap.h> #include <soc/clock.h> #include <soc/display.h> #include <soc/edp.h> #include <soc/gpio.h> #include <soc/grf.h> #include <soc/mmu_operations.h> #include <soc/mipi.h> #include <soc/soc.h> #include <soc/vop.h> #include <framebuffer_info.h> #include "chip.h" static void reset_edp(void) { /* rst edp */ write32(&cru_ptr->softrst_con[17], RK_SETBITS(1 << 12 | 1 << 13)); udelay(1); write32(&cru_ptr->softrst_con[17], RK_CLRBITS(1 << 12 | 1 << 13)); printk(BIOS_WARNING, "Retrying EDP initialization.\n"); } void rk_display_init(struct device *dev) { struct edid edid; struct soc_rockchip_rk3399_config *conf = dev->chip_info; enum vop_modes detected_mode = VOP_MODE_UNKNOWN; const struct mipi_panel_data *panel_data = NULL; int retry_count_init = 0; int retry_count_edp_prepare = 0; /* let's use vop0 in rk3399 */ uint32_t vop_id = 0; switch (conf->vop_mode) { case VOP_MODE_NONE: return; case VOP_MODE_EDP: printk(BIOS_DEBUG, "Attempting to set up EDP display.\n"); rkclk_configure_vop_aclk(vop_id, 200 * MHz); rkclk_configure_edp(25 * MHz); /* select edp signal from vop0 */ write32(&rk3399_grf->soc_con20, RK_CLRBITS(1 << 5)); /* select edp clk from SoC internal 24M crystal, otherwise, * it will source from edp's 24M clock (that depends on * edp vendor, could be unstable) */ write32(&rk3399_grf->soc_con25, RK_SETBITS(1 << 11)); retry_edp: /* Reset in case code jumped here. */ retry_count_init = 0; while (retry_count_init++ < 3) { rk_edp_init(); if (rk_edp_get_edid(&edid) == 0) { detected_mode = VOP_MODE_EDP; break; } if (retry_count_init == 3) { printk(BIOS_WARNING, "Warning: EDP initialization failed.\n"); return; } else { reset_edp(); } } break; case VOP_MODE_MIPI: printk(BIOS_DEBUG, "Attempting to setup MIPI display.\n"); rkclk_configure_mipi(); rkclk_configure_vop_aclk(vop_id, 200 * MHz); /* * disable tx0 turnrequest, turndisable, * forcetxstop, forcerxmode */ write32(&rk3399_grf->soc_con22, RK_CLRBITS(0xffff)); /* disable tx1 turndisable, forcetxstop, forcerxmode */ write32(&rk3399_grf->soc_con23, RK_CLRBITS(0xfff0)); /* * enable dphy_tx1rx1_masterslavez, * clear dphy_tx1rx1_enableclk, * clear dphy_tx1rx1_basedir, * disable tx1 turnrequest */ write32(&rk3399_grf->soc_con24, RK_CLRSETBITS(1 << 7 | 1 << 6 | 1 << 5 | 0xf, 1 << 7 | 0 << 6 | 0 << 5 | 0 << 0)); /* dphy_tx1rx1_enable */ write32(&rk3399_grf->soc_con23, RK_SETBITS(0xf)); /* select mipi-dsi0 and mipi-dsi1 signal from vop0 */ write32(&rk3399_grf->soc_con20, RK_CLRBITS((1 << 0) | (1 << 4))); panel_data = mainboard_get_mipi_mode(&edid.mode); if (panel_data) { if (panel_data->mipi_num > 1) detected_mode = VOP_MODE_DUAL_MIPI; else detected_mode = VOP_MODE_MIPI; } else { printk(BIOS_WARNING, "Can not get mipi panel data\n"); return; } break; default: printk(BIOS_WARNING, "Unsupported vop_mode, aborting.\n"); return; } if (rkclk_configure_vop_dclk(vop_id, edid.mode.pixel_clock * KHz)) { printk(BIOS_WARNING, "config vop err\n"); return; } edid_set_framebuffer_bits_per_pixel(&edid, conf->framebuffer_bits_per_pixel, 0); rkvop_mode_set(vop_id, &edid, detected_mode); rkvop_prepare(vop_id, &edid); switch (detected_mode) { case VOP_MODE_MIPI: case VOP_MODE_DUAL_MIPI: rk_mipi_prepare(&edid, panel_data); break; case VOP_MODE_EDP: /* will enable edp in depthcharge */ if (rk_edp_prepare()) { if (retry_count_edp_prepare++ < 3) { reset_edp(); /* Rerun entire init sequence */ goto retry_edp; } printk(BIOS_ERR, "EDP preparation failed."); return; } break; default: break; } mainboard_power_on_backlight(); fb_new_framebuffer_info_from_edid(&edid, (uintptr_t)0); return; }