This source file includes following definitions.
- _pingpong_offset
- dpu_hw_pp_setup_te_config
- dpu_hw_pp_poll_timeout_wr_ptr
- dpu_hw_pp_enable_te
- dpu_hw_pp_connect_external_te
- dpu_hw_pp_get_vsync_info
- dpu_hw_pp_get_line_count
- _setup_pingpong_ops
- dpu_hw_pingpong_init
- dpu_hw_pingpong_destroy
1
2
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"
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
31 static 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
52 static 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);
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
82 static 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
99 static 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
111 static 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
134 static 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
157 static 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)
171 return line;
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
180 return line;
181 }
182
183 static 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
194 static struct dpu_hw_blk_ops dpu_hw_ops;
195
196 struct 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;
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
217 dpu_hw_blk_init(&c->base, DPU_HW_BLK_PINGPONG, idx, &dpu_hw_ops);
218
219 return c;
220 }
221
222 void dpu_hw_pingpong_destroy(struct dpu_hw_pingpong *pp)
223 {
224 if (pp)
225 dpu_hw_blk_destroy(&pp->base);
226 kfree(pp);
227 }