1 // SPDX-License-Identifier: GPL-2.0-only
2 /* Copyright (c) 2015-2018, The Linux Foundation. All rights reserved.
6 #include "dpu_hw_catalog.h"
7 #include "dpu_hw_intf.h"
10 #define INTF_TIMING_ENGINE_EN 0x000
11 #define INTF_CONFIG 0x004
12 #define INTF_HSYNC_CTL 0x008
13 #define INTF_VSYNC_PERIOD_F0 0x00C
14 #define INTF_VSYNC_PERIOD_F1 0x010
15 #define INTF_VSYNC_PULSE_WIDTH_F0 0x014
16 #define INTF_VSYNC_PULSE_WIDTH_F1 0x018
17 #define INTF_DISPLAY_V_START_F0 0x01C
18 #define INTF_DISPLAY_V_START_F1 0x020
19 #define INTF_DISPLAY_V_END_F0 0x024
20 #define INTF_DISPLAY_V_END_F1 0x028
21 #define INTF_ACTIVE_V_START_F0 0x02C
22 #define INTF_ACTIVE_V_START_F1 0x030
23 #define INTF_ACTIVE_V_END_F0 0x034
24 #define INTF_ACTIVE_V_END_F1 0x038
25 #define INTF_DISPLAY_HCTL 0x03C
26 #define INTF_ACTIVE_HCTL 0x040
27 #define INTF_BORDER_COLOR 0x044
28 #define INTF_UNDERFLOW_COLOR 0x048
29 #define INTF_HSYNC_SKEW 0x04C
30 #define INTF_POLARITY_CTL 0x050
31 #define INTF_TEST_CTL 0x054
32 #define INTF_TP_COLOR0 0x058
33 #define INTF_TP_COLOR1 0x05C
34 #define INTF_FRAME_LINE_COUNT_EN 0x0A8
35 #define INTF_FRAME_COUNT 0x0AC
36 #define INTF_LINE_COUNT 0x0B0
38 #define INTF_DEFLICKER_CONFIG 0x0F0
39 #define INTF_DEFLICKER_STRNG_COEFF 0x0F4
40 #define INTF_DEFLICKER_WEAK_COEFF 0x0F8
42 #define INTF_DSI_CMD_MODE_TRIGGER_EN 0x084
43 #define INTF_PANEL_FORMAT 0x090
44 #define INTF_TPG_ENABLE 0x100
45 #define INTF_TPG_MAIN_CONTROL 0x104
46 #define INTF_TPG_VIDEO_CONFIG 0x108
47 #define INTF_TPG_COMPONENT_LIMITS 0x10C
48 #define INTF_TPG_RECTANGLE 0x110
49 #define INTF_TPG_INITIAL_VALUE 0x114
50 #define INTF_TPG_BLK_WHITE_PATTERN_FRAMES 0x118
51 #define INTF_TPG_RGB_MAPPING 0x11C
52 #define INTF_PROG_FETCH_START 0x170
53 #define INTF_PROG_ROT_START 0x174
55 #define INTF_FRAME_LINE_COUNT_EN 0x0A8
56 #define INTF_FRAME_COUNT 0x0AC
57 #define INTF_LINE_COUNT 0x0B0
59 #define INTF_MUX 0x25C
61 static const struct dpu_intf_cfg
*_intf_offset(enum dpu_intf intf
,
62 const struct dpu_mdss_cfg
*m
,
64 struct dpu_hw_blk_reg_map
*b
)
68 for (i
= 0; i
< m
->intf_count
; i
++) {
69 if ((intf
== m
->intf
[i
].id
) &&
70 (m
->intf
[i
].type
!= INTF_NONE
)) {
72 b
->blk_off
= m
->intf
[i
].base
;
73 b
->length
= m
->intf
[i
].len
;
74 b
->hwversion
= m
->hwversion
;
75 b
->log_mask
= DPU_DBG_MASK_INTF
;
80 return ERR_PTR(-EINVAL
);
83 static void dpu_hw_intf_setup_timing_engine(struct dpu_hw_intf
*ctx
,
84 const struct intf_timing_params
*p
,
85 const struct dpu_format
*fmt
)
87 struct dpu_hw_blk_reg_map
*c
= &ctx
->hw
;
88 u32 hsync_period
, vsync_period
;
89 u32 display_v_start
, display_v_end
;
90 u32 hsync_start_x
, hsync_end_x
;
91 u32 active_h_start
, active_h_end
;
92 u32 active_v_start
, active_v_end
;
93 u32 active_hctl
, display_hctl
, hsync_ctl
;
94 u32 polarity_ctl
, den_polarity
, hsync_polarity
, vsync_polarity
;
98 /* read interface_cfg */
99 intf_cfg
= DPU_REG_READ(c
, INTF_CONFIG
);
100 hsync_period
= p
->hsync_pulse_width
+ p
->h_back_porch
+ p
->width
+
102 vsync_period
= p
->vsync_pulse_width
+ p
->v_back_porch
+ p
->height
+
105 display_v_start
= ((p
->vsync_pulse_width
+ p
->v_back_porch
) *
106 hsync_period
) + p
->hsync_skew
;
107 display_v_end
= ((vsync_period
- p
->v_front_porch
) * hsync_period
) +
110 hsync_start_x
= p
->h_back_porch
+ p
->hsync_pulse_width
;
111 hsync_end_x
= hsync_period
- p
->h_front_porch
- 1;
113 if (p
->width
!= p
->xres
) {
114 active_h_start
= hsync_start_x
;
115 active_h_end
= active_h_start
+ p
->xres
- 1;
121 if (p
->height
!= p
->yres
) {
122 active_v_start
= display_v_start
;
123 active_v_end
= active_v_start
+ (p
->yres
* hsync_period
) - 1;
130 active_hctl
= (active_h_end
<< 16) | active_h_start
;
131 intf_cfg
|= BIT(29); /* ACTIVE_H_ENABLE */
137 intf_cfg
|= BIT(30); /* ACTIVE_V_ENABLE */
139 hsync_ctl
= (hsync_period
<< 16) | p
->hsync_pulse_width
;
140 display_hctl
= (hsync_end_x
<< 16) | hsync_start_x
;
142 if (ctx
->cap
->type
== INTF_EDP
|| ctx
->cap
->type
== INTF_DP
) {
143 active_h_start
= hsync_start_x
;
144 active_h_end
= active_h_start
+ p
->xres
- 1;
145 active_v_start
= display_v_start
;
146 active_v_end
= active_v_start
+ (p
->yres
* hsync_period
) - 1;
148 display_v_start
+= p
->hsync_pulse_width
+ p
->h_back_porch
;
150 active_hctl
= (active_h_end
<< 16) | active_h_start
;
151 display_hctl
= active_hctl
;
155 if (ctx
->cap
->type
== INTF_HDMI
) {
156 hsync_polarity
= p
->yres
>= 720 ? 0 : 1;
157 vsync_polarity
= p
->yres
>= 720 ? 0 : 1;
158 } else if (ctx
->cap
->type
== INTF_DP
) {
159 hsync_polarity
= p
->hsync_polarity
;
160 vsync_polarity
= p
->vsync_polarity
;
165 polarity_ctl
= (den_polarity
<< 2) | /* DEN Polarity */
166 (vsync_polarity
<< 1) | /* VSYNC Polarity */
167 (hsync_polarity
<< 0); /* HSYNC Polarity */
169 if (!DPU_FORMAT_IS_YUV(fmt
))
170 panel_format
= (fmt
->bits
[C0_G_Y
] |
171 (fmt
->bits
[C1_B_Cb
] << 2) |
172 (fmt
->bits
[C2_R_Cr
] << 4) |
175 /* Interface treats all the pixel data in RGB888 format */
176 panel_format
= (COLOR_8BIT
|
181 DPU_REG_WRITE(c
, INTF_HSYNC_CTL
, hsync_ctl
);
182 DPU_REG_WRITE(c
, INTF_VSYNC_PERIOD_F0
, vsync_period
* hsync_period
);
183 DPU_REG_WRITE(c
, INTF_VSYNC_PULSE_WIDTH_F0
,
184 p
->vsync_pulse_width
* hsync_period
);
185 DPU_REG_WRITE(c
, INTF_DISPLAY_HCTL
, display_hctl
);
186 DPU_REG_WRITE(c
, INTF_DISPLAY_V_START_F0
, display_v_start
);
187 DPU_REG_WRITE(c
, INTF_DISPLAY_V_END_F0
, display_v_end
);
188 DPU_REG_WRITE(c
, INTF_ACTIVE_HCTL
, active_hctl
);
189 DPU_REG_WRITE(c
, INTF_ACTIVE_V_START_F0
, active_v_start
);
190 DPU_REG_WRITE(c
, INTF_ACTIVE_V_END_F0
, active_v_end
);
191 DPU_REG_WRITE(c
, INTF_BORDER_COLOR
, p
->border_clr
);
192 DPU_REG_WRITE(c
, INTF_UNDERFLOW_COLOR
, p
->underflow_clr
);
193 DPU_REG_WRITE(c
, INTF_HSYNC_SKEW
, p
->hsync_skew
);
194 DPU_REG_WRITE(c
, INTF_POLARITY_CTL
, polarity_ctl
);
195 DPU_REG_WRITE(c
, INTF_FRAME_LINE_COUNT_EN
, 0x3);
196 DPU_REG_WRITE(c
, INTF_CONFIG
, intf_cfg
);
197 DPU_REG_WRITE(c
, INTF_PANEL_FORMAT
, panel_format
);
200 static void dpu_hw_intf_enable_timing_engine(
201 struct dpu_hw_intf
*intf
,
204 struct dpu_hw_blk_reg_map
*c
= &intf
->hw
;
205 /* Note: Display interface select is handled in top block hw layer */
206 DPU_REG_WRITE(c
, INTF_TIMING_ENGINE_EN
, enable
!= 0);
209 static void dpu_hw_intf_setup_prg_fetch(
210 struct dpu_hw_intf
*intf
,
211 const struct intf_prog_fetch
*fetch
)
213 struct dpu_hw_blk_reg_map
*c
= &intf
->hw
;
217 * Fetch should always be outside the active lines. If the fetching
218 * is programmed within active region, hardware behavior is unknown.
221 fetch_enable
= DPU_REG_READ(c
, INTF_CONFIG
);
223 fetch_enable
|= BIT(31);
224 DPU_REG_WRITE(c
, INTF_PROG_FETCH_START
,
227 fetch_enable
&= ~BIT(31);
230 DPU_REG_WRITE(c
, INTF_CONFIG
, fetch_enable
);
233 static void dpu_hw_intf_bind_pingpong_blk(
234 struct dpu_hw_intf
*intf
,
236 const enum dpu_pingpong pp
)
238 struct dpu_hw_blk_reg_map
*c
= &intf
->hw
;
241 mux_cfg
= DPU_REG_READ(c
, INTF_MUX
);
245 mux_cfg
|= (pp
- PINGPONG_0
) & 0x7;
249 DPU_REG_WRITE(c
, INTF_MUX
, mux_cfg
);
252 static void dpu_hw_intf_get_status(
253 struct dpu_hw_intf
*intf
,
254 struct intf_status
*s
)
256 struct dpu_hw_blk_reg_map
*c
= &intf
->hw
;
258 s
->is_en
= DPU_REG_READ(c
, INTF_TIMING_ENGINE_EN
);
260 s
->frame_count
= DPU_REG_READ(c
, INTF_FRAME_COUNT
);
261 s
->line_count
= DPU_REG_READ(c
, INTF_LINE_COUNT
);
268 static u32
dpu_hw_intf_get_line_count(struct dpu_hw_intf
*intf
)
270 struct dpu_hw_blk_reg_map
*c
;
277 return DPU_REG_READ(c
, INTF_LINE_COUNT
);
280 static void _setup_intf_ops(struct dpu_hw_intf_ops
*ops
,
283 ops
->setup_timing_gen
= dpu_hw_intf_setup_timing_engine
;
284 ops
->setup_prg_fetch
= dpu_hw_intf_setup_prg_fetch
;
285 ops
->get_status
= dpu_hw_intf_get_status
;
286 ops
->enable_timing
= dpu_hw_intf_enable_timing_engine
;
287 ops
->get_line_count
= dpu_hw_intf_get_line_count
;
288 if (cap
& BIT(DPU_INTF_INPUT_CTRL
))
289 ops
->bind_pingpong_blk
= dpu_hw_intf_bind_pingpong_blk
;
292 static struct dpu_hw_blk_ops dpu_hw_ops
;
294 struct dpu_hw_intf
*dpu_hw_intf_init(enum dpu_intf idx
,
296 const struct dpu_mdss_cfg
*m
)
298 struct dpu_hw_intf
*c
;
299 const struct dpu_intf_cfg
*cfg
;
301 c
= kzalloc(sizeof(*c
), GFP_KERNEL
);
303 return ERR_PTR(-ENOMEM
);
305 cfg
= _intf_offset(idx
, m
, addr
, &c
->hw
);
306 if (IS_ERR_OR_NULL(cfg
)) {
308 pr_err("failed to create dpu_hw_intf %d\n", idx
);
309 return ERR_PTR(-EINVAL
);
318 _setup_intf_ops(&c
->ops
, c
->cap
->features
);
320 dpu_hw_blk_init(&c
->base
, DPU_HW_BLK_INTF
, idx
, &dpu_hw_ops
);
325 void dpu_hw_intf_destroy(struct dpu_hw_intf
*intf
)
328 dpu_hw_blk_destroy(&intf
->base
);