]> git.proxmox.com Git - mirror_ubuntu-jammy-kernel.git/blame - drivers/gpu/drm/msm/disp/dpu1/dpu_hw_pingpong.c
treewide: Replace GPLv2 boilerplate/reference with SPDX - rule 284
[mirror_ubuntu-jammy-kernel.git] / drivers / gpu / drm / msm / disp / dpu1 / dpu_hw_pingpong.c
CommitLineData
97fb5e8d 1// SPDX-License-Identifier: GPL-2.0-only
25fdd593 2/* Copyright (c) 2015-2018, The Linux Foundation. All rights reserved.
25fdd593
JS
3 */
4
5#include <linux/iopoll.h>
6
7#include "dpu_hw_mdss.h"
8#include "dpu_hwio.h"
9#include "dpu_hw_catalog.h"
10#include "dpu_hw_pingpong.h"
25fdd593
JS
11#include "dpu_kms.h"
12#include "dpu_trace.h"
13
14#define PP_TEAR_CHECK_EN 0x000
15#define PP_SYNC_CONFIG_VSYNC 0x004
16#define PP_SYNC_CONFIG_HEIGHT 0x008
17#define PP_SYNC_WRCOUNT 0x00C
18#define PP_VSYNC_INIT_VAL 0x010
19#define PP_INT_COUNT_VAL 0x014
20#define PP_SYNC_THRESH 0x018
21#define PP_START_POS 0x01C
22#define PP_RD_PTR_IRQ 0x020
23#define PP_WR_PTR_IRQ 0x024
24#define PP_OUT_LINE_COUNT 0x028
25#define PP_LINE_COUNT 0x02C
26
27#define PP_FBC_MODE 0x034
28#define PP_FBC_BUDGET_CTL 0x038
29#define PP_FBC_LOSSY_MODE 0x03C
30
31static struct dpu_pingpong_cfg *_pingpong_offset(enum dpu_pingpong pp,
32 struct dpu_mdss_cfg *m,
33 void __iomem *addr,
34 struct dpu_hw_blk_reg_map *b)
35{
36 int i;
37
38 for (i = 0; i < m->pingpong_count; i++) {
39 if (pp == m->pingpong[i].id) {
40 b->base_off = addr;
41 b->blk_off = m->pingpong[i].base;
42 b->length = m->pingpong[i].len;
43 b->hwversion = m->hwversion;
44 b->log_mask = DPU_DBG_MASK_PINGPONG;
45 return &m->pingpong[i];
46 }
47 }
48
49 return ERR_PTR(-EINVAL);
50}
51
52static int dpu_hw_pp_setup_te_config(struct dpu_hw_pingpong *pp,
53 struct dpu_hw_tear_check *te)
54{
55 struct dpu_hw_blk_reg_map *c;
56 int cfg;
57
58 if (!pp || !te)
59 return -EINVAL;
60 c = &pp->hw;
61
62 cfg = BIT(19); /*VSYNC_COUNTER_EN */
63 if (te->hw_vsync_mode)
64 cfg |= BIT(20);
65
66 cfg |= te->vsync_count;
67
68 DPU_REG_WRITE(c, PP_SYNC_CONFIG_VSYNC, cfg);
69 DPU_REG_WRITE(c, PP_SYNC_CONFIG_HEIGHT, te->sync_cfg_height);
70 DPU_REG_WRITE(c, PP_VSYNC_INIT_VAL, te->vsync_init_val);
71 DPU_REG_WRITE(c, PP_RD_PTR_IRQ, te->rd_ptr_irq);
72 DPU_REG_WRITE(c, PP_START_POS, te->start_pos);
73 DPU_REG_WRITE(c, PP_SYNC_THRESH,
74 ((te->sync_threshold_continue << 16) |
75 te->sync_threshold_start));
76 DPU_REG_WRITE(c, PP_SYNC_WRCOUNT,
77 (te->start_pos + te->sync_threshold_start + 1));
78
79 return 0;
80}
81
82static int dpu_hw_pp_poll_timeout_wr_ptr(struct dpu_hw_pingpong *pp,
83 u32 timeout_us)
84{
85 struct dpu_hw_blk_reg_map *c;
86 u32 val;
87 int rc;
88
89 if (!pp)
90 return -EINVAL;
91
92 c = &pp->hw;
93 rc = readl_poll_timeout(c->base_off + c->blk_off + PP_LINE_COUNT,
94 val, (val & 0xffff) >= 1, 10, timeout_us);
95
96 return rc;
97}
98
99static int dpu_hw_pp_enable_te(struct dpu_hw_pingpong *pp, bool enable)
100{
101 struct dpu_hw_blk_reg_map *c;
102
103 if (!pp)
104 return -EINVAL;
105 c = &pp->hw;
106
107 DPU_REG_WRITE(c, PP_TEAR_CHECK_EN, enable);
108 return 0;
109}
110
111static int dpu_hw_pp_connect_external_te(struct dpu_hw_pingpong *pp,
112 bool enable_external_te)
113{
114 struct dpu_hw_blk_reg_map *c = &pp->hw;
115 u32 cfg;
116 int orig;
117
118 if (!pp)
119 return -EINVAL;
120
121 c = &pp->hw;
122 cfg = DPU_REG_READ(c, PP_SYNC_CONFIG_VSYNC);
123 orig = (bool)(cfg & BIT(20));
124 if (enable_external_te)
125 cfg |= BIT(20);
126 else
127 cfg &= ~BIT(20);
128 DPU_REG_WRITE(c, PP_SYNC_CONFIG_VSYNC, cfg);
129 trace_dpu_pp_connect_ext_te(pp->idx - PINGPONG_0, cfg);
130
131 return orig;
132}
133
134static int dpu_hw_pp_get_vsync_info(struct dpu_hw_pingpong *pp,
135 struct dpu_hw_pp_vsync_info *info)
136{
137 struct dpu_hw_blk_reg_map *c;
138 u32 val;
139
140 if (!pp || !info)
141 return -EINVAL;
142 c = &pp->hw;
143
144 val = DPU_REG_READ(c, PP_VSYNC_INIT_VAL);
145 info->rd_ptr_init_val = val & 0xffff;
146
147 val = DPU_REG_READ(c, PP_INT_COUNT_VAL);
148 info->rd_ptr_frame_count = (val & 0xffff0000) >> 16;
149 info->rd_ptr_line_count = val & 0xffff;
150
151 val = DPU_REG_READ(c, PP_LINE_COUNT);
152 info->wr_ptr_line_count = val & 0xffff;
153
154 return 0;
155}
156
157static u32 dpu_hw_pp_get_line_count(struct dpu_hw_pingpong *pp)
158{
159 struct dpu_hw_blk_reg_map *c = &pp->hw;
160 u32 height, init;
161 u32 line = 0xFFFF;
162
163 if (!pp)
164 return 0;
165 c = &pp->hw;
166
167 init = DPU_REG_READ(c, PP_VSYNC_INIT_VAL) & 0xFFFF;
168 height = DPU_REG_READ(c, PP_SYNC_CONFIG_HEIGHT) & 0xFFFF;
169
170 if (height < init)
0841851f 171 return line;
25fdd593
JS
172
173 line = DPU_REG_READ(c, PP_INT_COUNT_VAL) & 0xFFFF;
174
175 if (line < init)
176 line += (0xFFFF - init);
177 else
178 line -= init;
179
25fdd593
JS
180 return line;
181}
182
183static void _setup_pingpong_ops(struct dpu_hw_pingpong_ops *ops,
184 const struct dpu_pingpong_cfg *hw_cap)
185{
186 ops->setup_tearcheck = dpu_hw_pp_setup_te_config;
187 ops->enable_tearcheck = dpu_hw_pp_enable_te;
188 ops->connect_external_te = dpu_hw_pp_connect_external_te;
189 ops->get_vsync_info = dpu_hw_pp_get_vsync_info;
190 ops->poll_timeout_wr_ptr = dpu_hw_pp_poll_timeout_wr_ptr;
191 ops->get_line_count = dpu_hw_pp_get_line_count;
192};
193
53edf462 194static struct dpu_hw_blk_ops dpu_hw_ops;
25fdd593
JS
195
196struct dpu_hw_pingpong *dpu_hw_pingpong_init(enum dpu_pingpong idx,
197 void __iomem *addr,
198 struct dpu_mdss_cfg *m)
199{
200 struct dpu_hw_pingpong *c;
201 struct dpu_pingpong_cfg *cfg;
25fdd593
JS
202
203 c = kzalloc(sizeof(*c), GFP_KERNEL);
204 if (!c)
205 return ERR_PTR(-ENOMEM);
206
207 cfg = _pingpong_offset(idx, m, addr, &c->hw);
208 if (IS_ERR_OR_NULL(cfg)) {
209 kfree(c);
210 return ERR_PTR(-EINVAL);
211 }
212
213 c->idx = idx;
214 c->caps = cfg;
215 _setup_pingpong_ops(&c->ops, c->caps);
216
53edf462 217 dpu_hw_blk_init(&c->base, DPU_HW_BLK_PINGPONG, idx, &dpu_hw_ops);
25fdd593
JS
218
219 return c;
25fdd593
JS
220}
221
222void dpu_hw_pingpong_destroy(struct dpu_hw_pingpong *pp)
223{
224 if (pp)
225 dpu_hw_blk_destroy(&pp->base);
226 kfree(pp);
227}