• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* SPDX-License-Identifier: GPL-2.0-only OR MIT */
2 
3 #include <console/console.h>
4 #include <device/mmio.h>
5 #include <edid.h>
6 #include <soc/addressmap.h>
7 #include <soc/ddp.h>
8 
9 #define MERGE_MODE	6
10 #define MERGE_SWAP	0
11 
disp_config_main_path_connection(void)12 static void disp_config_main_path_connection(void)
13 {
14 	/* ovl0 */
15 	write32(&mmsys_cfg->mmsys_ovl_mout_en,
16 		DISP_OVL0_TO_DISP_RDMA0);
17 	write32(&mmsys_cfg->mmsys_sel_in,
18 		SEL_IN_DSC_WRAP0_IN_FROM_DISP_DITHER0 |
19 		SEL_IN_VPP_MERGE_FROM_DSC_WRAP0_OUT |
20 		SEL_IN_DP_INTF0_FROM_VPP_MERGE);
21 	write32(&mmsys_cfg->mmsys_sel_out,
22 		SEL_OUT_DISP_DITHER0_TO_DSC_WRAP0_IN |
23 		SEL_OUT_DSC_WRAP0_OUT_TO_VPP_MERGE |
24 		SEL_OUT_VPP_MERGE_TO_DP_INTF0);
25 }
26 
disp_config_main_path_mutex(void)27 static void disp_config_main_path_mutex(void)
28 {
29 	write32(&disp_mutex->mutex[0].mod, MUTEX_MOD_MAIN_PATH);
30 
31 	/* Clock source from DP_INTF0 */
32 	write32(&disp_mutex->mutex[0].ctl,
33 		MUTEX_SOF_DP_INTF0 | (MUTEX_SOF_DP_INTF0 << 7));
34 	write32(&disp_mutex->mutex[0].en, BIT(0));
35 }
36 
ovl_bgclr_in_sel(u32 idx)37 static void ovl_bgclr_in_sel(u32 idx)
38 {
39 	setbits32(&disp_ovl[idx]->datapath_con, BIT(2));
40 }
41 
ovl_layer_smi_id_en(u32 idx)42 static void ovl_layer_smi_id_en(u32 idx)
43 {
44 	setbits32(&disp_ovl[idx]->datapath_con, BIT(0));
45 }
46 
ovl_layer_gclast_en(u32 idx)47 static void ovl_layer_gclast_en(u32 idx)
48 {
49 	setbits32(&disp_ovl[idx]->datapath_con, BIT(24));
50 	setbits32(&disp_ovl[idx]->datapath_con, BIT(25));
51 }
52 
ovl_layer_output_clamp_en(u32 idx)53 static void ovl_layer_output_clamp_en(u32 idx)
54 {
55 	setbits32(&disp_ovl[idx]->datapath_con, BIT(26));
56 }
57 
ccorr_config(u32 width,u32 height)58 static void ccorr_config(u32 width, u32 height)
59 {
60 	struct disp_ccorr_regs *const regs = disp_ccorr;
61 
62 	write32(&regs->size, width << 16 | height);
63 	clrsetbits32(&regs->cfg, PQ_ENGINE_EN, PQ_RELAY_MODE);
64 	write32(&regs->en, PQ_EN);
65 }
66 
aal_config(u32 width,u32 height)67 static void aal_config(u32 width, u32 height)
68 {
69 	struct disp_aal_regs *const regs = disp_aal;
70 
71 	write32(&regs->size, width << 16 | height);
72 	write32(&regs->output_size, width << 16 | height);
73 	clrsetbits32(&regs->cfg, PQ_ENGINE_EN, PQ_RELAY_MODE);
74 	write32(&regs->en, PQ_EN);
75 }
76 
gamma_config(u32 width,u32 height)77 static void gamma_config(u32 width, u32 height)
78 {
79 	struct disp_gamma_regs *const regs = disp_gamma;
80 
81 	write32(&regs->size, width << 16 | height);
82 	setbits32(&regs->cfg, PQ_RELAY_MODE);
83 	write32(&regs->en, PQ_EN);
84 }
85 
dither_config(u32 width,u32 height)86 static void dither_config(u32 width, u32 height)
87 {
88 	struct disp_dither_regs *const regs = disp_dither;
89 	write32(&regs->size, width << 16 | height);
90 	setbits32(&regs->cfg, PQ_RELAY_MODE);
91 	write32(&regs->en, PQ_EN);
92 }
93 
dsc_config(void)94 static void dsc_config(void)
95 {
96 	struct disp_dsc_regs *const regs = disp_dsc;
97 
98 	/* Enable dsc bypass mode. */
99 	write32(&regs->con, DISP_DSC0_CON);
100 }
101 
merge_config(u32 width,u32 height)102 static void merge_config(u32 width, u32 height)
103 {
104 	struct disp_merge_regs *const regs = disp_merge;
105 
106 	write32(&regs->cfg0, height << 16 | width);
107 	write32(&regs->cfg4, height << 16 | width);
108 	write32(&regs->cfg25, height << 16 | width);
109 	setbits32(&regs->cfg10, MERGE_SWAP);
110 	setbits32(&regs->cfg12, MERGE_MODE);
111 	write32(&regs->en, 0x1);
112 }
113 
main_disp_path_setup(u32 width,u32 height,u32 vrefresh)114 static void main_disp_path_setup(u32 width, u32 height, u32 vrefresh)
115 {
116 	u32 idx = 0;
117 	u32 pixel_clk = width * height * vrefresh;
118 
119 	for (idx = 0; idx < MAIN_PATH_OVL_NR; idx++) {
120 		ovl_set_roi(idx, width, height, idx ? 0 : 0xff0000ff);
121 		ovl_layer_smi_id_en(idx);
122 		ovl_layer_gclast_en(idx);
123 		ovl_layer_output_clamp_en(idx);
124 	}
125 
126 	rdma_config(width, height, pixel_clk, 5 * KiB);
127 	color_start(width, height);
128 	ccorr_config(width, height);
129 	aal_config(width, height);
130 	gamma_config(width, height);
131 	dither_config(width, height);
132 	dsc_config();
133 	merge_config(width, height);
134 	disp_config_main_path_connection();
135 	disp_config_main_path_mutex();
136 }
137 
disp_clock_on(void)138 static void disp_clock_on(void)
139 {
140 	clrbits32(&mmsys_cfg->mmsys_cg_con0, CG_CON0_DISP_ALL);
141 	clrbits32(&mmsys_cfg->mmsys_cg_con1, CG_CON1_DISP_ALL);
142 	clrbits32(&mmsys_cfg->mmsys_cg_con2, CG_CON2_DISP_ALL);
143 }
144 
mtk_ddp_init(void)145 void mtk_ddp_init(void)
146 {
147 	disp_clock_on();
148 
149 	/* Turn off M4U port. */
150 	write32((void *)(SMI_LARB0 + SMI_LARB_PORT_L0_OVL_RDMA0), 0);
151 }
152 
mtk_ddp_mode_set(const struct edid * edid,enum disp_path_sel path)153 void mtk_ddp_mode_set(const struct edid *edid, enum disp_path_sel path)
154 {
155 	u32 fmt = OVL_INFMT_RGBA8888;
156 	u32 bpp = edid->framebuffer_bits_per_pixel / 8;
157 	u32 width = edid->mode.ha;
158 	u32 height = edid->mode.va;
159 	u32 vrefresh = edid->mode.refresh;
160 
161 	printk(BIOS_DEBUG, "%s: display resolution: %dx%d@%d bpp %d\n",
162 	       __func__, width, height, vrefresh, bpp);
163 
164 	if (!vrefresh) {
165 		if (!width || !height)
166 			vrefresh = 60;
167 		else
168 			vrefresh = edid->mode.pixel_clock * 1000 /
169 				   ((width + edid->mode.hbl) *
170 				    (height + edid->mode.vbl));
171 
172 		printk(BIOS_WARNING, "%s: vrefresh is not provided; using %d\n",
173 		       __func__, vrefresh);
174 	}
175 
176 	main_disp_path_setup(width, height, vrefresh);
177 	rdma_start();
178 	ovl_layer_config(fmt, bpp, width, height);
179 	ovl_bgclr_in_sel(1);
180 }
181