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(®s->size, width << 16 | height);
63 clrsetbits32(®s->cfg, PQ_ENGINE_EN, PQ_RELAY_MODE);
64 write32(®s->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(®s->size, width << 16 | height);
72 write32(®s->output_size, width << 16 | height);
73 clrsetbits32(®s->cfg, PQ_ENGINE_EN, PQ_RELAY_MODE);
74 write32(®s->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(®s->size, width << 16 | height);
82 setbits32(®s->cfg, PQ_RELAY_MODE);
83 write32(®s->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(®s->size, width << 16 | height);
90 setbits32(®s->cfg, PQ_RELAY_MODE);
91 write32(®s->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(®s->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(®s->cfg0, height << 16 | width);
107 write32(®s->cfg4, height << 16 | width);
108 write32(®s->cfg25, height << 16 | width);
109 setbits32(®s->cfg10, MERGE_SWAP);
110 setbits32(®s->cfg12, MERGE_MODE);
111 write32(®s->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