1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3 * Copyright (C) Fuzhou Rockchip Electronics Co.Ltd
4 * Author:Mark Yao <mark.yao@rock-chips.com>
5 */
6
7 #include <linux/clk.h>
8 #include <linux/component.h>
9 #include <linux/debugfs.h>
10 #include <linux/delay.h>
11 #include <linux/fixp-arith.h>
12 #include <linux/iopoll.h>
13 #include <linux/kernel.h>
14 #include <linux/mfd/syscon.h>
15 #include <linux/module.h>
16 #include <linux/of.h>
17 #include <linux/of_device.h>
18 #include <linux/overflow.h>
19 #include <linux/platform_device.h>
20 #include <linux/pm_runtime.h>
21 #include <linux/regmap.h>
22 #include <linux/reset.h>
23 #include <linux/sort.h>
24
25 #include <drm/drm.h>
26 #include <drm/drm_atomic.h>
27 #include <drm/drm_atomic_uapi.h>
28 #include <drm/drm_crtc.h>
29 #include <drm/drm_crtc_helper.h>
30 #include <drm/drm_debugfs.h>
31 #include <drm/drm_flip_work.h>
32 #include <drm/drm_fourcc.h>
33 #include <drm/drm_gem_framebuffer_helper.h>
34 #include <drm/drm_plane_helper.h>
35 #include <drm/drm_probe_helper.h>
36 #include <drm/drm_self_refresh_helper.h>
37 #include <drm/drm_vblank.h>
38
39 #ifdef CONFIG_DRM_ANALOGIX_DP
40 #include <drm/bridge/analogix_dp.h>
41 #endif
42 #include <dt-bindings/soc/rockchip-system-status.h>
43
44 #include <soc/rockchip/rockchip_dmc.h>
45 #include <soc/rockchip/rockchip-system-status.h>
46 #include <uapi/linux/videodev2.h>
47 #include "../drm_crtc_internal.h"
48
49 #include "rockchip_drm_drv.h"
50 #include "rockchip_drm_gem.h"
51 #include "rockchip_drm_fb.h"
52 #include "rockchip_drm_vop.h"
53 #include "rockchip_rgb.h"
54
55 #define VOP_REG_SUPPORT(vop, reg) \
56 ((reg).mask && \
57 (!(reg).major || ((reg).major == VOP_MAJOR((vop)->version) && (reg).begin_minor <= VOP_MINOR((vop)->version) && \
58 (reg).end_minor >= VOP_MINOR((vop)->version))))
59
60 #define VOP_WIN_SUPPORT(vop, win, name) VOP_REG_SUPPORT(vop, (win)->phy->name)
61
62 #define VOP_WIN_SCL_EXT_SUPPORT(vop, win, name) ((win)->phy->scl->ext && \
63 VOP_REG_SUPPORT(vop, (win)->phy->scl->ext->name))
64
65 #define VOP_CTRL_SUPPORT(vop, name) VOP_REG_SUPPORT(vop, (vop)->data->ctrl->name)
66
67 #define VOP_INTR_SUPPORT(vop, name) VOP_REG_SUPPORT(vop, (vop)->data->intr->name)
68
69 #define REG_SET_EX(x, off, mask, shift, v, write_mask, relaxed) \
70 vop_mask_write((x), (off), (mask), (shift), (v), (write_mask), (relaxed))
71
72 #define REG_SET_E(vop, name, off, reg, mask, v, relaxed) \
73 do { \
74 if (VOP_REG_SUPPORT(vop, reg)) \
75 REG_SET_EX(vop, (off) + (reg).offset, mask, (reg).shift, v, (reg).write_mask, relaxed); \
76 else \
77 dev_dbg((vop)->dev, "Warning: not support " #name "\n"); \
78 } while (0)
79
80 #define REG_SET(x, name, off, reg, v, relaxed) REG_SET_E(x, name, off, reg, (reg).mask, v, relaxed)
81 #define REG_SET_MASK(x, name, off, reg, mask, v, relaxed) \
82 REG_SET_E((x), (name), (off), (reg), (reg).mask &(mask), (v), (relaxed))
83
84 #define VOP_WIN_SET(x, win, name, v) REG_SET((x), (name), (win)->offset, VOP_WIN_NAME(win, name), (v), true)
85 #define VOP_WIN_SET_EXT(x, win, ext, name, v) REG_SET((x), (name), 0, (win)->ext->name, (v), true)
86 #define VOP_SCL_SET(x, win, name, v) REG_SET((x), (name), (win)->offset, (win)->phy->scl->name, (v), true)
87 #define VOP_SCL_SET_EXT(x, win, name, v) REG_SET((x), (name), (win)->offset, (win)->phy->scl->ext->name, (v), true)
88
89 #define VOP_CTRL_SET(x, name, v) REG_SET((x), (name), 0, (x)->data->ctrl->name, (v), false)
90
91 #define VOP_INTR_GET(vop, name) vop_read_reg((vop), 0, &(vop)->data->ctrl->name)
92
93 #define VOP_INTR_SET(vop, name, v) REG_SET((vop), name, 0, (vop)->data->intr->name, v, false)
94 #define VOP_INTR_SET_MASK(vop, name, mask, v) REG_SET_MASK((vop), name, 0, (vop)->data->intr->name, mask, v, false)
95
96 #define VOP_REG_SET(vop, group, name, v) vop_reg_set((vop), &(vop)->data->group->name, 0, ~0, (v), #name)
97
98 #define VOP_INTR_SET_TYPE(vop, name, type, v) \
99 do { \
100 int i, reg = 0, mask = 0; \
101 for (i = 0; i < (vop)->data->intr->nintrs; i++) { \
102 if ((vop)->data->intr->intrs[i] & (type)) { \
103 reg |= (v) << i; \
104 mask |= 1 << i; \
105 } \
106 } \
107 VOP_INTR_SET_MASK(vop, name, mask, reg); \
108 } while (0)
109 #define VOP_INTR_GET_TYPE(vop, name, type) vop_get_intr_type((vop), &(vop)->data->intr->name, (type))
110
111 #define VOP_CTRL_GET(x, name) vop_read_reg((x), 0, &vop->data->ctrl->name)
112
113 #define VOP_WIN_GET(vop, win, name) vop_read_reg((vop), (win)->offset, &VOP_WIN_NAME(win, name))
114
115 #define VOP_WIN_NAME(win, name) (vop_get_win_phy((win), &(win)->phy->name)->name)
116
117 #define VOP_WIN_TO_INDEX(vop_win) ((vop_win) - (vop_win)->vop->win)
118
119 #define VOP_GRF_SET(vop, reg, v) \
120 do { \
121 if ((vop)->data->grf_ctrl) { \
122 vop_grf_writel((vop), (vop)->data->grf_ctrl->reg, (v)); \
123 } \
124 } while (0)
125
126 #define to_vop_win(x) container_of((x), struct vop_win, base)
127 #define to_vop_plane_state(x) container_of((x), struct vop_plane_state, base)
128
129 enum vop_pending {
130 VOP_PENDING_FB_UNREF,
131 };
132
133 struct vop_zpos {
134 int win_id;
135 int zpos;
136 };
137
138 struct vop_plane_state {
139 struct drm_plane_state base;
140 int format;
141 int zpos;
142 struct drm_rect src;
143 struct drm_rect dest;
144 dma_addr_t yrgb_mst;
145 dma_addr_t uv_mst;
146 const uint32_t *y2r_table;
147 const uint32_t *r2r_table;
148 const uint32_t *r2y_table;
149 int eotf;
150 bool y2r_en;
151 bool r2r_en;
152 bool r2y_en;
153 int color_space;
154 u32 color_key;
155 unsigned int csc_mode;
156 int global_alpha;
157 int blend_mode;
158 unsigned long offset;
159 int pdaf_data_type;
160 bool async_commit;
161 struct vop_dump_list *planlist;
162 };
163
164 struct rockchip_mcu_timing {
165 int mcu_pix_total;
166 int mcu_cs_pst;
167 int mcu_cs_pend;
168 int mcu_rw_pst;
169 int mcu_rw_pend;
170 int mcu_hold_mode;
171 };
172
173 struct vop_win {
174 struct vop_win *parent;
175 struct drm_plane base;
176
177 int win_id;
178 int area_id;
179 u8 plane_id; /* unique plane id */
180 const char *name;
181
182 int zpos;
183 uint32_t offset;
184 enum drm_plane_type type;
185 const struct vop_win_phy *phy;
186 const struct vop_csc *csc;
187 const uint32_t *data_formats;
188 uint32_t nformats;
189 const uint64_t *format_modifiers;
190 u64 feature;
191 struct vop *vop;
192 struct vop_plane_state state;
193
194 struct drm_property *input_width_prop;
195 struct drm_property *input_height_prop;
196 struct drm_property *output_width_prop;
197 struct drm_property *output_height_prop;
198 struct drm_property *color_key_prop;
199 struct drm_property *scale_prop;
200 struct drm_property *name_prop;
201 };
202
203 struct vop {
204 struct rockchip_crtc rockchip_crtc;
205 struct device *dev;
206 struct drm_device *drm_dev;
207 struct dentry *debugfs;
208 struct drm_info_list *debugfs_files;
209 struct drm_property *plane_feature_prop;
210 struct drm_property *plane_mask_prop;
211 struct drm_property *feature_prop;
212
213 bool is_iommu_enabled;
214 bool is_iommu_needed;
215 bool is_enabled;
216 bool support_multi_area;
217
218 u32 version;
219 u32 background;
220 u32 line_flag;
221 u8 id;
222 u8 plane_mask;
223 u64 soc_id;
224 struct drm_prop_enum_list *plane_name_list;
225
226 struct drm_tv_connector_state active_tv_state;
227 bool pre_overlay;
228 bool loader_protect;
229 struct completion dsp_hold_completion;
230
231 /* protected by dev->event_lock */
232 struct drm_pending_vblank_event *event;
233
234 struct drm_flip_work fb_unref_work;
235 unsigned long pending;
236
237 struct completion line_flag_completion;
238
239 const struct vop_data *data;
240 int num_wins;
241
242 uint32_t *regsbak;
243 void __iomem *regs;
244 struct regmap *grf;
245
246 /* physical map length of vop register */
247 uint32_t len;
248
249 void __iomem *lut_regs;
250 u32 *lut;
251 u32 lut_len;
252 bool lut_active;
253 /* gamma look up table */
254 struct drm_color_lut *gamma_lut;
255 bool dual_channel_swap;
256 /* one time only one process allowed to config the register */
257 spinlock_t reg_lock;
258 /* lock vop irq reg */
259 spinlock_t irq_lock;
260 /* protects crtc enable/disable */
261 struct mutex vop_lock;
262
263 unsigned int irq;
264
265 /* vop AHP clk */
266 struct clk *hclk;
267 /* vop dclk */
268 struct clk *dclk;
269 /* vop share memory frequency */
270 struct clk *aclk;
271 /* vop source handling, optional */
272 struct clk *dclk_source;
273
274 /* vop dclk reset */
275 struct reset_control *dclk_rst;
276
277 struct rockchip_dclk_pll *pll;
278
279 struct rockchip_mcu_timing mcu_timing;
280
281 struct vop_win win[];
282 };
283
284 /*
285 * bus-format types.
286 */
287 struct drm_bus_format_enum_list {
288 int type;
289 const char *name;
290 };
291
292 static const struct drm_bus_format_enum_list drm_bus_format_enum_list_ex[] = {
293 {DRM_MODE_CONNECTOR_Unknown, "Unknown"},
294 {MEDIA_BUS_FMT_RGB565_1X16, "RGB565_1X16"},
295 {MEDIA_BUS_FMT_RGB666_1X18, "RGB666_1X18"},
296 {MEDIA_BUS_FMT_RGB666_1X24_CPADHI, "RGB666_1X24_CPADHI"},
297 {MEDIA_BUS_FMT_RGB666_1X7X3_SPWG, "RGB666_1X7X3_SPWG"},
298 {MEDIA_BUS_FMT_YUV8_1X24, "YUV8_1X24"},
299 {MEDIA_BUS_FMT_UYYVYY8_0_5X24, "UYYVYY8_0_5X24"},
300 {MEDIA_BUS_FMT_YUV10_1X30, "YUV10_1X30"},
301 {MEDIA_BUS_FMT_UYYVYY10_0_5X30, "UYYVYY10_0_5X30"},
302 {MEDIA_BUS_FMT_RGB888_3X8, "RGB888_3X8"},
303 {MEDIA_BUS_FMT_RGB888_DUMMY_4X8, "RGB888_DUMMY_4X8"},
304 {MEDIA_BUS_FMT_RGB888_1X24, "RGB888_1X24"},
305 {MEDIA_BUS_FMT_RGB888_1X7X4_SPWG, "RGB888_1X7X4_SPWG"},
306 {MEDIA_BUS_FMT_RGB888_1X7X4_JEIDA, "RGB888_1X7X4_JEIDA"},
307 {MEDIA_BUS_FMT_UYVY8_2X8, "UYVY8_2X8"},
308 {MEDIA_BUS_FMT_YUYV8_1X16, "YUYV8_1X16"},
309 {MEDIA_BUS_FMT_UYVY8_1X16, "UYVY8_1X16"},
310 };
311
DRM_ENUM_NAME_FN(drm_get_bus_format_name,drm_bus_format_enum_list_ex)312 static DRM_ENUM_NAME_FN(drm_get_bus_format_name, drm_bus_format_enum_list_ex)
313
314 static inline struct vop *to_vop(struct drm_crtc *crtc)
315 {
316 struct rockchip_crtc *rockchip_crtc;
317
318 rockchip_crtc = container_of(crtc, struct rockchip_crtc, crtc);
319
320 return container_of(rockchip_crtc, struct vop, rockchip_crtc);
321 }
322
vop_lock(struct vop * vop)323 static void vop_lock(struct vop *vop)
324 {
325 mutex_lock(&vop->vop_lock);
326 rockchip_dmcfreq_lock();
327 }
328
vop_unlock(struct vop * vop)329 static void vop_unlock(struct vop *vop)
330 {
331 rockchip_dmcfreq_unlock();
332 mutex_unlock(&vop->vop_lock);
333 }
334
vop_grf_writel(struct vop * vop,struct vop_reg reg,u32 v)335 static inline void vop_grf_writel(struct vop *vop, struct vop_reg reg, u32 v)
336 {
337 u32 val = 0;
338
339 if (IS_ERR_OR_NULL(vop->grf)) {
340 return;
341 }
342
343 if (VOP_REG_SUPPORT(vop, reg)) {
344 val = (v << reg.shift) | (reg.mask << (reg.shift + 0x10));
345 regmap_write(vop->grf, reg.offset, val);
346 }
347 }
348
vop_writel(struct vop * vop,uint32_t offset,uint32_t v)349 static inline void vop_writel(struct vop *vop, uint32_t offset, uint32_t v)
350 {
351 writel(v, vop->regs + offset);
352 vop->regsbak[offset >> 0x2] = v;
353 }
354
vop_readl(struct vop * vop,uint32_t offset)355 static inline uint32_t vop_readl(struct vop *vop, uint32_t offset)
356 {
357 return readl(vop->regs + offset);
358 }
359
vop_read_reg(struct vop * vop,uint32_t base,const struct vop_reg * reg)360 static inline uint32_t vop_read_reg(struct vop *vop, uint32_t base, const struct vop_reg *reg)
361 {
362 return (vop_readl(vop, base + reg->offset) >> reg->shift) & reg->mask;
363 }
364
vop_mask_write(struct vop * vop,uint32_t offset,uint32_t mask,uint32_t shift,uint32_t v,bool write_mask,bool relaxed)365 static inline void vop_mask_write(struct vop *vop, uint32_t offset, uint32_t mask, uint32_t shift, uint32_t v,
366 bool write_mask, bool relaxed)
367 {
368 if (!mask) {
369 return;
370 }
371
372 if (write_mask) {
373 v = ((v & mask) << shift) | (mask << (shift + 0x10));
374 } else {
375 uint32_t cached_val = vop->regsbak[offset >> 0x2];
376
377 v = (cached_val & ~(mask << shift)) | ((v & mask) << shift);
378 vop->regsbak[offset >> 0x2] = v;
379 }
380
381 if (relaxed) {
382 writel_relaxed(v, vop->regs + offset);
383 } else {
384 writel(v, vop->regs + offset);
385 }
386 }
387
vop_get_win_phy(struct vop_win * win,const struct vop_reg * reg)388 static inline const struct vop_win_phy *vop_get_win_phy(struct vop_win *win, const struct vop_reg *reg)
389 {
390 if (!reg->mask && win->parent) {
391 return win->parent->phy;
392 }
393
394 return win->phy;
395 }
396
vop_get_intr_type(struct vop * vop,const struct vop_reg * reg,int type)397 static inline uint32_t vop_get_intr_type(struct vop *vop, const struct vop_reg *reg, int type)
398 {
399 uint32_t i, ret = 0;
400 uint32_t regs = vop_read_reg(vop, 0, reg);
401
402 for (i = 0; i < vop->data->intr->nintrs; i++) {
403 if ((type & vop->data->intr->intrs[i]) && (regs & (1 << i))) {
404 ret |= vop->data->intr->intrs[i];
405 }
406 }
407
408 return ret;
409 }
410
vop_load_hdr2sdr_table(struct vop * vop)411 static void vop_load_hdr2sdr_table(struct vop *vop)
412 {
413 int i;
414 const struct vop_hdr_table *table = vop->data->hdr_table;
415 uint32_t hdr2sdr_eetf_oetf_yn[0x21];
416
417 for (i = 0; i < 0x21; i++) {
418 hdr2sdr_eetf_oetf_yn[i] = table->hdr2sdr_eetf_yn[i] + (table->hdr2sdr_bt1886oetf_yn[i] << 0x10);
419 }
420
421 vop_writel(vop, table->hdr2sdr_eetf_oetf_y0_offset, hdr2sdr_eetf_oetf_yn[0]);
422 for (i = 0x1; i < 0x21; i++) {
423 vop_writel(vop, table->hdr2sdr_eetf_oetf_y1_offset + (i - 1) * 0x4, hdr2sdr_eetf_oetf_yn[i]);
424 }
425
426 vop_writel(vop, table->hdr2sdr_sat_y0_offset, table->hdr2sdr_sat_yn[0]);
427 for (i = 0x1; i < 0x9; i++) {
428 vop_writel(vop, table->hdr2sdr_sat_y1_offset + (i - 1) * 0x4, table->hdr2sdr_sat_yn[i]);
429 }
430
431 VOP_CTRL_SET(vop, hdr2sdr_src_min, table->hdr2sdr_src_range_min);
432 VOP_CTRL_SET(vop, hdr2sdr_src_max, table->hdr2sdr_src_range_max);
433 VOP_CTRL_SET(vop, hdr2sdr_normfaceetf, table->hdr2sdr_normfaceetf);
434 VOP_CTRL_SET(vop, hdr2sdr_dst_min, table->hdr2sdr_dst_range_min);
435 VOP_CTRL_SET(vop, hdr2sdr_dst_max, table->hdr2sdr_dst_range_max);
436 VOP_CTRL_SET(vop, hdr2sdr_normfacgamma, table->hdr2sdr_normfacgamma);
437 }
438
vop_load_sdr2hdr_table(struct vop * vop,uint32_t cmd)439 static void vop_load_sdr2hdr_table(struct vop *vop, uint32_t cmd)
440 {
441 int i;
442 const struct vop_hdr_table *table = vop->data->hdr_table;
443 uint32_t sdr2hdr_eotf_oetf_yn[0x41];
444 uint32_t sdr2hdr_oetf_dx_dxpow[0x40];
445
446 for (i = 0; i < 0x41; i++) {
447 if (cmd == SDR2HDR_FOR_BT2020) {
448 sdr2hdr_eotf_oetf_yn[i] =
449 table->sdr2hdr_bt1886eotf_yn_for_bt2020[i] + (table->sdr2hdr_st2084oetf_yn_for_bt2020[i] << 0x12);
450 } else if (cmd == SDR2HDR_FOR_HDR) {
451 sdr2hdr_eotf_oetf_yn[i] =
452 table->sdr2hdr_bt1886eotf_yn_for_hdr[i] + (table->sdr2hdr_st2084oetf_yn_for_hdr[i] << 0x12);
453 } else if (cmd == SDR2HDR_FOR_HLG_HDR) {
454 sdr2hdr_eotf_oetf_yn[i] =
455 table->sdr2hdr_bt1886eotf_yn_for_hlg_hdr[i] + (table->sdr2hdr_st2084oetf_yn_for_hlg_hdr[i] << 0x12);
456 }
457 }
458 vop_writel(vop, table->sdr2hdr_eotf_oetf_y0_offset, sdr2hdr_eotf_oetf_yn[0]);
459 for (i = 1; i < 0x41; i++) {
460 vop_writel(vop, table->sdr2hdr_eotf_oetf_y1_offset + (i - 1) * 0x4, sdr2hdr_eotf_oetf_yn[i]);
461 }
462
463 for (i = 0; i < 0x40; i++) {
464 sdr2hdr_oetf_dx_dxpow[i] = table->sdr2hdr_st2084oetf_dxn[i] + (table->sdr2hdr_st2084oetf_dxn_pow2[i] << 0x10);
465 vop_writel(vop, table->sdr2hdr_oetf_dx_dxpow1_offset + i * 0x4, sdr2hdr_oetf_dx_dxpow[i]);
466 }
467
468 for (i = 0; i < 0x3f; i++) {
469 vop_writel(vop, table->sdr2hdr_oetf_xn1_offset + i * 0x4, table->sdr2hdr_st2084oetf_xn[i]);
470 }
471 }
472
vop_load_csc_table(struct vop * vop,u32 offset,const u32 * table)473 static void vop_load_csc_table(struct vop *vop, u32 offset, const u32 *table)
474 {
475 int i;
476
477 /*
478 * so far the csc offset is not 0 and in the feature the csc offset
479 * impossible be 0, so when the offset is 0, should return here.
480 */
481 if (!table || offset == 0) {
482 return;
483 }
484
485 for (i = 0; i < 0x8; i++) {
486 vop_writel(vop, offset + i * 0x4, table[i]);
487 }
488 }
489
vop_cfg_done(struct vop * vop)490 static inline void vop_cfg_done(struct vop *vop)
491 {
492 VOP_CTRL_SET(vop, cfg_done, 1);
493 }
494
vop_is_allwin_disabled(struct vop * vop)495 static bool vop_is_allwin_disabled(struct vop *vop)
496 {
497 int i;
498
499 for (i = 0; i < vop->num_wins; i++) {
500 struct vop_win *win = &vop->win[i];
501
502 if (VOP_WIN_GET(vop, win, enable) != 0) {
503 return false;
504 }
505 }
506
507 return true;
508 }
509
vop_win_disable(struct vop * vop,struct vop_win * win)510 static void vop_win_disable(struct vop *vop, struct vop_win *win)
511 {
512 /*
513 * FIXUP: some of the vop scale would be abnormal after windows power
514 * on/off so deinit scale to scale_none mode.
515 */
516 if (win->phy->scl && win->phy->scl->ext) {
517 VOP_SCL_SET_EXT(vop, win, yrgb_hor_scl_mode, SCALE_NONE);
518 VOP_SCL_SET_EXT(vop, win, yrgb_ver_scl_mode, SCALE_NONE);
519 VOP_SCL_SET_EXT(vop, win, cbcr_hor_scl_mode, SCALE_NONE);
520 VOP_SCL_SET_EXT(vop, win, cbcr_ver_scl_mode, SCALE_NONE);
521 }
522
523 VOP_WIN_SET(vop, win, enable, 0);
524 if (win->area_id == 0) {
525 VOP_WIN_SET(vop, win, gate, 0);
526 }
527 }
528
vop_disable_allwin(struct vop * vop)529 static void vop_disable_allwin(struct vop *vop)
530 {
531 int i;
532
533 for (i = 0; i < vop->num_wins; i++) {
534 struct vop_win *win = &vop->win[i];
535
536 vop_win_disable(vop, win);
537 }
538 }
539
vop_write_lut(struct vop * vop,uint32_t offset,uint32_t v)540 static inline void vop_write_lut(struct vop *vop, uint32_t offset, uint32_t v)
541 {
542 writel(v, vop->lut_regs + offset);
543 }
544
vop_read_lut(struct vop * vop,uint32_t offset)545 static inline uint32_t vop_read_lut(struct vop *vop, uint32_t offset)
546 {
547 return readl(vop->lut_regs + offset);
548 }
549
has_rb_swapped(uint32_t format)550 static bool has_rb_swapped(uint32_t format)
551 {
552 switch (format) {
553 case DRM_FORMAT_XBGR8888:
554 case DRM_FORMAT_ABGR8888:
555 case DRM_FORMAT_BGR888:
556 case DRM_FORMAT_BGR565:
557 return true;
558 default:
559 return false;
560 }
561 }
562
vop_convert_format(uint32_t format)563 static enum vop_data_format vop_convert_format(uint32_t format)
564 {
565 switch (format) {
566 case DRM_FORMAT_XRGB8888:
567 case DRM_FORMAT_ARGB8888:
568 case DRM_FORMAT_XBGR8888:
569 case DRM_FORMAT_ABGR8888:
570 return VOP_FMT_ARGB8888;
571 case DRM_FORMAT_RGB888:
572 case DRM_FORMAT_BGR888:
573 return VOP_FMT_RGB888;
574 case DRM_FORMAT_RGB565:
575 case DRM_FORMAT_BGR565:
576 return VOP_FMT_RGB565;
577 case DRM_FORMAT_NV12:
578 case DRM_FORMAT_NV15:
579 return VOP_FMT_YUV420SP;
580 case DRM_FORMAT_NV16:
581 case DRM_FORMAT_NV20:
582 return VOP_FMT_YUV422SP;
583 case DRM_FORMAT_NV24:
584 case DRM_FORMAT_NV30:
585 return VOP_FMT_YUV444SP;
586 case DRM_FORMAT_YVYU:
587 case DRM_FORMAT_VYUY:
588 case DRM_FORMAT_YUYV:
589 case DRM_FORMAT_UYVY:
590 return VOP_FMT_YUYV;
591 default:
592 DRM_ERROR("unsupported format[%08x]\n", format);
593 return -EINVAL;
594 }
595 }
596
is_uv_swap(uint32_t bus_format,uint32_t output_mode)597 static bool is_uv_swap(uint32_t bus_format, uint32_t output_mode)
598 {
599 /*
600 * There is no media type for YUV444 output,
601 * so when out_mode is AAAA or P888, assume output is YUV444 on
602 * yuv format.
603 *
604 * From H/W testing, YUV444 mode need a rb swap.
605 */
606 if (bus_format == MEDIA_BUS_FMT_YVYU8_1X16 || bus_format == MEDIA_BUS_FMT_VYUY8_1X16 ||
607 bus_format == MEDIA_BUS_FMT_YVYU8_2X8 || bus_format == MEDIA_BUS_FMT_VYUY8_2X8 ||
608 ((bus_format == MEDIA_BUS_FMT_YUV8_1X24 || bus_format == MEDIA_BUS_FMT_YUV10_1X30) &&
609 (output_mode == ROCKCHIP_OUT_MODE_AAAA || output_mode == ROCKCHIP_OUT_MODE_P888))) {
610 return true;
611 } else {
612 return false;
613 }
614 }
615
is_yc_swap(uint32_t bus_format)616 static bool is_yc_swap(uint32_t bus_format)
617 {
618 switch (bus_format) {
619 case MEDIA_BUS_FMT_YUYV8_1X16:
620 case MEDIA_BUS_FMT_YVYU8_1X16:
621 case MEDIA_BUS_FMT_YUYV8_2X8:
622 case MEDIA_BUS_FMT_YVYU8_2X8:
623 return true;
624 default:
625 return false;
626 }
627 }
628
is_yuv_output(uint32_t bus_format)629 static bool is_yuv_output(uint32_t bus_format)
630 {
631 switch (bus_format) {
632 case MEDIA_BUS_FMT_YUV8_1X24:
633 case MEDIA_BUS_FMT_YUV10_1X30:
634 case MEDIA_BUS_FMT_UYYVYY8_0_5X24:
635 case MEDIA_BUS_FMT_UYYVYY10_0_5X30:
636 case MEDIA_BUS_FMT_YUYV8_2X8:
637 case MEDIA_BUS_FMT_YVYU8_2X8:
638 case MEDIA_BUS_FMT_UYVY8_2X8:
639 case MEDIA_BUS_FMT_VYUY8_2X8:
640 case MEDIA_BUS_FMT_YUYV8_1X16:
641 case MEDIA_BUS_FMT_YVYU8_1X16:
642 case MEDIA_BUS_FMT_UYVY8_1X16:
643 case MEDIA_BUS_FMT_VYUY8_1X16:
644 return true;
645 default:
646 return false;
647 }
648 }
649
is_yuv_support(uint32_t format)650 static bool is_yuv_support(uint32_t format)
651 {
652 switch (format) {
653 case DRM_FORMAT_NV12:
654 case DRM_FORMAT_NV15:
655 case DRM_FORMAT_NV16:
656 case DRM_FORMAT_NV20:
657 case DRM_FORMAT_NV24:
658 case DRM_FORMAT_NV30:
659 case DRM_FORMAT_YVYU:
660 case DRM_FORMAT_VYUY:
661 case DRM_FORMAT_YUYV:
662 case DRM_FORMAT_UYVY:
663 return true;
664 default:
665 return false;
666 }
667 }
668
is_yuyv_format(uint32_t format)669 static bool is_yuyv_format(uint32_t format)
670 {
671 switch (format) {
672 case DRM_FORMAT_YVYU:
673 case DRM_FORMAT_VYUY:
674 case DRM_FORMAT_YUYV:
675 case DRM_FORMAT_UYVY:
676 return true;
677 default:
678 return false;
679 }
680 }
681
is_yuv_10bit(uint32_t format)682 static bool is_yuv_10bit(uint32_t format)
683 {
684 switch (format) {
685 case DRM_FORMAT_NV15:
686 case DRM_FORMAT_NV20:
687 case DRM_FORMAT_NV30:
688 return true;
689 default:
690 return false;
691 }
692 }
693
is_alpha_support(uint32_t format)694 static bool is_alpha_support(uint32_t format)
695 {
696 switch (format) {
697 case DRM_FORMAT_ARGB8888:
698 case DRM_FORMAT_ABGR8888:
699 return true;
700 default:
701 return false;
702 }
703 }
704
rockchip_afbc(struct drm_plane * plane,u64 modifier)705 static inline bool rockchip_afbc(struct drm_plane *plane, u64 modifier)
706 {
707 int i;
708
709 if (modifier == DRM_FORMAT_MOD_LINEAR) {
710 return false;
711 }
712
713 for (i = 0; i < plane->modifier_count; i++) {
714 if (plane->modifiers[i] == modifier) {
715 break;
716 }
717 }
718
719 return (i < plane->modifier_count) ? true : false;
720 }
721
scl_vop_cal_scale(enum scale_mode mode,uint32_t src,uint32_t dst,bool is_horizontal,int vsu_mode,int * vskiplines)722 static uint16_t scl_vop_cal_scale(enum scale_mode mode, uint32_t src, uint32_t dst, bool is_horizontal, int vsu_mode,
723 int *vskiplines)
724 {
725 uint16_t val = 1 << SCL_FT_DEFAULT_FIXPOINT_SHIFT;
726
727 if (vskiplines) {
728 *vskiplines = 0;
729 }
730
731 if (is_horizontal) {
732 if (mode == SCALE_UP) {
733 val = GET_SCL_FT_BIC(src, dst);
734 } else if (mode == SCALE_DOWN) {
735 val = GET_SCL_FT_BILI_DN(src, dst);
736 }
737 } else {
738 if (mode == SCALE_UP) {
739 if (vsu_mode == SCALE_UP_BIL) {
740 val = GET_SCL_FT_BILI_UP(src, dst);
741 } else {
742 val = GET_SCL_FT_BIC(src, dst);
743 }
744 } else if (mode == SCALE_DOWN) {
745 if (vskiplines) {
746 *vskiplines = scl_get_vskiplines(src, dst);
747 val = scl_get_bili_dn_vskip(src, dst, *vskiplines);
748 } else {
749 val = GET_SCL_FT_BILI_DN(src, dst);
750 }
751 }
752 }
753
754 return val;
755 }
756
scl_vop_cal_scl_fac(struct vop * vop,const struct vop_win * win,uint32_t src_w,uint32_t src_h,uint32_t dst_w,uint32_t dst_h,uint32_t pixel_format)757 static void scl_vop_cal_scl_fac(struct vop *vop, const struct vop_win *win, uint32_t src_w, uint32_t src_h,
758 uint32_t dst_w, uint32_t dst_h, uint32_t pixel_format)
759 {
760 uint16_t yrgb_hor_scl_mode, yrgb_ver_scl_mode;
761 uint16_t cbcr_hor_scl_mode = SCALE_NONE;
762 uint16_t cbcr_ver_scl_mode = SCALE_NONE;
763 const struct drm_format_info *info = drm_format_info(pixel_format);
764 uint8_t hsub = info->hsub;
765 uint8_t vsub = info->vsub;
766 bool is_yuv = false;
767 uint16_t cbcr_src_w = src_w / hsub;
768 uint16_t cbcr_src_h = src_h / vsub;
769 uint16_t vsu_mode;
770 uint16_t lb_mode;
771 uint32_t val;
772 const struct vop_data *vop_data = vop->data;
773 int vskiplines;
774
775 if (!win->phy->scl) {
776 return;
777 }
778
779 if (!(vop_data->feature & VOP_FEATURE_ALPHA_SCALE)) {
780 if (is_alpha_support(pixel_format) && (src_w != dst_w || src_h != dst_h)) {
781 DRM_ERROR("ERROR: unsupported ppixel alpha&scale\n");
782 }
783 }
784
785 if (info->is_yuv) {
786 is_yuv = true;
787 }
788
789 if (!win->phy->scl->ext) {
790 VOP_SCL_SET(vop, win, scale_yrgb_x, scl_cal_scale2(src_w, dst_w));
791 VOP_SCL_SET(vop, win, scale_yrgb_y, scl_cal_scale2(src_h, dst_h));
792 if (is_yuv) {
793 VOP_SCL_SET(vop, win, scale_cbcr_x, scl_cal_scale2(cbcr_src_w, dst_w));
794 VOP_SCL_SET(vop, win, scale_cbcr_y, scl_cal_scale2(cbcr_src_h, dst_h));
795 }
796 return;
797 }
798
799 yrgb_hor_scl_mode = scl_get_scl_mode(src_w, dst_w);
800 yrgb_ver_scl_mode = scl_get_scl_mode(src_h, dst_h);
801
802 if (is_yuv) {
803 cbcr_hor_scl_mode = scl_get_scl_mode(cbcr_src_w, dst_w);
804 cbcr_ver_scl_mode = scl_get_scl_mode(cbcr_src_h, dst_h);
805 if (cbcr_hor_scl_mode == SCALE_DOWN) {
806 lb_mode = scl_vop_cal_lb_mode(dst_w, true);
807 } else {
808 lb_mode = scl_vop_cal_lb_mode(cbcr_src_w, true);
809 }
810 } else {
811 if (yrgb_hor_scl_mode == SCALE_DOWN) {
812 lb_mode = scl_vop_cal_lb_mode(dst_w, false);
813 } else {
814 lb_mode = scl_vop_cal_lb_mode(src_w, false);
815 }
816 }
817
818 VOP_SCL_SET_EXT(vop, win, lb_mode, lb_mode);
819 if (lb_mode == LB_RGB_3840X2) {
820 if (yrgb_ver_scl_mode != SCALE_NONE) {
821 DRM_DEV_ERROR(vop->dev, "not allow yrgb ver scale\n");
822 return;
823 }
824 if (cbcr_ver_scl_mode != SCALE_NONE) {
825 DRM_DEV_ERROR(vop->dev, "not allow cbcr ver scale\n");
826 return;
827 }
828 vsu_mode = SCALE_UP_BIL;
829 } else if (lb_mode == LB_RGB_2560X4) {
830 vsu_mode = SCALE_UP_BIL;
831 } else {
832 vsu_mode = SCALE_UP_BIC;
833 }
834
835 val = scl_vop_cal_scale(yrgb_hor_scl_mode, src_w, dst_w, true, 0, NULL);
836 VOP_SCL_SET(vop, win, scale_yrgb_x, val);
837 val = scl_vop_cal_scale(yrgb_ver_scl_mode, src_h, dst_h, false, vsu_mode, &vskiplines);
838 VOP_SCL_SET(vop, win, scale_yrgb_y, val);
839
840 VOP_SCL_SET_EXT(vop, win, vsd_yrgb_gt4, vskiplines == 0x4);
841 VOP_SCL_SET_EXT(vop, win, vsd_yrgb_gt2, vskiplines == 0x2);
842
843 VOP_SCL_SET_EXT(vop, win, yrgb_hor_scl_mode, yrgb_hor_scl_mode);
844 VOP_SCL_SET_EXT(vop, win, yrgb_ver_scl_mode, yrgb_ver_scl_mode);
845 VOP_SCL_SET_EXT(vop, win, yrgb_hsd_mode, SCALE_DOWN_BIL);
846 VOP_SCL_SET_EXT(vop, win, yrgb_vsd_mode, SCALE_DOWN_BIL);
847 VOP_SCL_SET_EXT(vop, win, yrgb_vsu_mode, vsu_mode);
848 if (is_yuv) {
849 val = scl_vop_cal_scale(cbcr_hor_scl_mode, cbcr_src_w, dst_w, true, 0, NULL);
850 VOP_SCL_SET(vop, win, scale_cbcr_x, val);
851 val = scl_vop_cal_scale(cbcr_ver_scl_mode, cbcr_src_h, dst_h, false, vsu_mode, &vskiplines);
852 VOP_SCL_SET(vop, win, scale_cbcr_y, val);
853
854 VOP_SCL_SET_EXT(vop, win, vsd_cbcr_gt4, vskiplines == 0x4);
855 VOP_SCL_SET_EXT(vop, win, vsd_cbcr_gt2, vskiplines == 0x2);
856 VOP_SCL_SET_EXT(vop, win, cbcr_hor_scl_mode, cbcr_hor_scl_mode);
857 VOP_SCL_SET_EXT(vop, win, cbcr_ver_scl_mode, cbcr_ver_scl_mode);
858 VOP_SCL_SET_EXT(vop, win, cbcr_hsd_mode, SCALE_DOWN_BIL);
859 VOP_SCL_SET_EXT(vop, win, cbcr_vsd_mode, SCALE_DOWN_BIL);
860 VOP_SCL_SET_EXT(vop, win, cbcr_vsu_mode, vsu_mode);
861 }
862 }
863
864 /*
865 * rk3328 HDR/CSC path
866 *
867 * HDR/SDR --> win0 --> HDR2SDR ----\
868 * \ MUX --\
869 * \ --> SDR2HDR/CSC--/ \
870 * \
871 * SDR --> win1 -->pre_overlay ->SDR2HDR/CSC --> post_ovrlay-->post CSC-->output
872 * SDR --> win2 -/
873 *
874 */
875
vop_hdr_atomic_check(struct drm_crtc * crtc,struct drm_crtc_state * crtc_state)876 static int vop_hdr_atomic_check(struct drm_crtc *crtc, struct drm_crtc_state *crtc_state)
877 {
878 struct drm_atomic_state *state = crtc_state->state;
879 struct rockchip_crtc_state *s = to_rockchip_crtc_state(crtc_state);
880 struct drm_plane_state *pstate;
881 struct drm_plane *plane;
882 struct vop *vop = to_vop(crtc);
883 int pre_sdr2hdr_state = 0, post_sdr2hdr_state = 0;
884 int pre_sdr2hdr_mode = 0, post_sdr2hdr_mode = 0, sdr2hdr_func = 0;
885 bool pre_overlay = false;
886 int hdr2sdr_en = 0, plane_id = 0;
887
888 if (!vop->data->hdr_table) {
889 return 0;
890 }
891 /* hdr cover */
892 drm_atomic_crtc_state_for_each_plane(plane, crtc_state)
893 {
894 struct vop_plane_state *vop_plane_state;
895 struct vop_win *win = to_vop_win(plane);
896
897 pstate = drm_atomic_get_plane_state(state, plane);
898 if (IS_ERR(pstate)) {
899 return PTR_ERR(pstate);
900 }
901 vop_plane_state = to_vop_plane_state(pstate);
902 if (!pstate->fb) {
903 continue;
904 }
905
906 if (vop_plane_state->eotf > s->eotf) {
907 if (win->feature & WIN_FEATURE_HDR2SDR) {
908 hdr2sdr_en = 1;
909 }
910 }
911 if (vop_plane_state->eotf < s->eotf) {
912 if (win->feature & WIN_FEATURE_PRE_OVERLAY) {
913 pre_sdr2hdr_state |= BIT(plane_id);
914 } else {
915 post_sdr2hdr_state |= BIT(plane_id);
916 }
917 }
918 plane_id++;
919 }
920
921 if (pre_sdr2hdr_state || post_sdr2hdr_state || hdr2sdr_en) {
922 pre_overlay = true;
923 pre_sdr2hdr_mode = BT709_TO_BT2020;
924 post_sdr2hdr_mode = BT709_TO_BT2020;
925 sdr2hdr_func = SDR2HDR_FOR_HDR;
926 goto exit_hdr_convert;
927 }
928
929 /* overlay mode */
930 plane_id = 0;
931 pre_overlay = false;
932 pre_sdr2hdr_mode = 0;
933 post_sdr2hdr_mode = 0;
934 pre_sdr2hdr_state = 0;
935 post_sdr2hdr_state = 0;
936 drm_atomic_crtc_state_for_each_plane(plane, crtc_state)
937 {
938 struct vop_plane_state *vop_plane_state;
939 struct vop_win *win = to_vop_win(plane);
940
941 pstate = drm_atomic_get_plane_state(state, plane);
942 if (IS_ERR(pstate)) {
943 return PTR_ERR(pstate);
944 }
945 vop_plane_state = to_vop_plane_state(pstate);
946 if (!pstate->fb) {
947 continue;
948 }
949
950 if (vop_plane_state->color_space == V4L2_COLORSPACE_BT2020 && vop_plane_state->color_space > s->color_space) {
951 if (win->feature & WIN_FEATURE_PRE_OVERLAY) {
952 pre_sdr2hdr_mode = BT2020_TO_BT709;
953 pre_sdr2hdr_state |= BIT(plane_id);
954 } else {
955 post_sdr2hdr_mode = BT2020_TO_BT709;
956 post_sdr2hdr_state |= BIT(plane_id);
957 }
958 }
959 if (s->color_space == V4L2_COLORSPACE_BT2020 && vop_plane_state->color_space < s->color_space) {
960 if (win->feature & WIN_FEATURE_PRE_OVERLAY) {
961 pre_sdr2hdr_mode = BT709_TO_BT2020;
962 pre_sdr2hdr_state |= BIT(plane_id);
963 } else {
964 post_sdr2hdr_mode = BT709_TO_BT2020;
965 post_sdr2hdr_state |= BIT(plane_id);
966 }
967 }
968 plane_id++;
969 }
970
971 if (pre_sdr2hdr_state || post_sdr2hdr_state) {
972 pre_overlay = true;
973 sdr2hdr_func = SDR2HDR_FOR_BT2020;
974 }
975
976 exit_hdr_convert:
977 s->hdr.pre_overlay = pre_overlay;
978 s->hdr.hdr2sdr_en = hdr2sdr_en;
979 if (s->hdr.pre_overlay) {
980 s->yuv_overlay = 0;
981 }
982
983 s->hdr.sdr2hdr_state.bt1886eotf_pre_conv_en = !!pre_sdr2hdr_state;
984 s->hdr.sdr2hdr_state.rgb2rgb_pre_conv_en = !!pre_sdr2hdr_state;
985 s->hdr.sdr2hdr_state.rgb2rgb_pre_conv_mode = pre_sdr2hdr_mode;
986 s->hdr.sdr2hdr_state.st2084oetf_pre_conv_en = !!pre_sdr2hdr_state;
987
988 s->hdr.sdr2hdr_state.bt1886eotf_post_conv_en = !!post_sdr2hdr_state;
989 s->hdr.sdr2hdr_state.rgb2rgb_post_conv_en = !!post_sdr2hdr_state;
990 s->hdr.sdr2hdr_state.rgb2rgb_post_conv_mode = post_sdr2hdr_mode;
991 s->hdr.sdr2hdr_state.st2084oetf_post_conv_en = !!post_sdr2hdr_state;
992 s->hdr.sdr2hdr_state.sdr2hdr_func = sdr2hdr_func;
993
994 return 0;
995 }
996
to_vop_csc_mode(int csc_mode)997 static int to_vop_csc_mode(int csc_mode)
998 {
999 switch (csc_mode) {
1000 case V4L2_COLORSPACE_SMPTE170M:
1001 case V4L2_COLORSPACE_470_SYSTEM_M:
1002 case V4L2_COLORSPACE_470_SYSTEM_BG:
1003 return CSC_BT601L;
1004 case V4L2_COLORSPACE_REC709:
1005 case V4L2_COLORSPACE_SMPTE240M:
1006 case V4L2_COLORSPACE_DEFAULT:
1007 return CSC_BT709L;
1008 case V4L2_COLORSPACE_JPEG:
1009 return CSC_BT601F;
1010 case V4L2_COLORSPACE_BT2020:
1011 return CSC_BT2020;
1012 default:
1013 return CSC_BT709L;
1014 }
1015 }
1016
vop_disable_all_planes(struct vop * vop)1017 static void vop_disable_all_planes(struct vop *vop)
1018 {
1019 bool active;
1020 int ret;
1021
1022 vop_disable_allwin(vop);
1023 vop_cfg_done(vop);
1024 ret = readx_poll_timeout_atomic(vop_is_allwin_disabled, vop, active, active, 0, 0x7a120);
1025 if (ret) {
1026 dev_err(vop->dev, "wait win close timeout\n");
1027 }
1028 }
1029
1030 /*
1031 * rk3399 colorspace path:
1032 * Input Win csc Output
1033 * 1. YUV(2020) --> Y2R->2020To709->R2Y --> YUV_OUTPUT(601/709)
1034 * RGB --> R2Y __/
1035 *
1036 * 2. YUV(2020) --> bypasss --> YUV_OUTPUT(2020)
1037 * RGB --> 709To2020->R2Y __/
1038 *
1039 * 3. YUV(2020) --> Y2R->2020To709 --> RGB_OUTPUT(709)
1040 * RGB --> R2Y __/
1041 *
1042 * 4. YUV(601/709)-> Y2R->709To2020->R2Y --> YUV_OUTPUT(2020)
1043 * RGB --> 709To2020->R2Y __/
1044 *
1045 * 5. YUV(601/709)-> bypass --> YUV_OUTPUT(709)
1046 * RGB --> R2Y __/
1047 *
1048 * 6. YUV(601/709)-> bypass --> YUV_OUTPUT(601)
1049 * RGB --> R2Y(601) __/
1050 *
1051 * 7. YUV --> Y2R(709) --> RGB_OUTPUT(709)
1052 * RGB --> bypass __/
1053 *
1054 * 8. RGB --> 709To2020->R2Y --> YUV_OUTPUT(2020)
1055 *
1056 * 9. RGB --> R2Y(709) --> YUV_OUTPUT(709)
1057 *
1058 * 10. RGB --> R2Y(601) --> YUV_OUTPUT(601)
1059 *
1060 * 11. RGB --> bypass --> RGB_OUTPUT(709)
1061 */
vop_setup_csc_table(const struct vop_csc_table * csc_table,bool is_input_yuv,bool is_output_yuv,int input_csc,int output_csc,const uint32_t ** y2r_table,const uint32_t ** r2r_table,const uint32_t ** r2y_table)1062 static int vop_setup_csc_table(const struct vop_csc_table *csc_table, bool is_input_yuv, bool is_output_yuv,
1063 int input_csc, int output_csc, const uint32_t **y2r_table, const uint32_t **r2r_table,
1064 const uint32_t **r2y_table)
1065 {
1066 *y2r_table = NULL;
1067 *r2r_table = NULL;
1068 *r2y_table = NULL;
1069
1070 if (!csc_table) {
1071 return 0;
1072 }
1073
1074 if (is_output_yuv) {
1075 if (output_csc == V4L2_COLORSPACE_BT2020) {
1076 if (is_input_yuv) {
1077 if (input_csc == V4L2_COLORSPACE_BT2020) {
1078 return 0;
1079 }
1080 *y2r_table = csc_table->y2r_bt709;
1081 }
1082 if (input_csc != V4L2_COLORSPACE_BT2020) {
1083 *r2r_table = csc_table->r2r_bt709_to_bt2020;
1084 }
1085 *r2y_table = csc_table->r2y_bt2020;
1086 } else {
1087 if (is_input_yuv && input_csc == V4L2_COLORSPACE_BT2020) {
1088 *y2r_table = csc_table->y2r_bt2020;
1089 }
1090 if (input_csc == V4L2_COLORSPACE_BT2020) {
1091 *r2r_table = csc_table->r2r_bt2020_to_bt709;
1092 }
1093 if (!is_input_yuv || *y2r_table) {
1094 if (output_csc == V4L2_COLORSPACE_REC709 || output_csc == V4L2_COLORSPACE_SMPTE240M ||
1095 output_csc == V4L2_COLORSPACE_DEFAULT) {
1096 *r2y_table = csc_table->r2y_bt709;
1097 } else if (output_csc == V4L2_COLORSPACE_SMPTE170M || output_csc == V4L2_COLORSPACE_470_SYSTEM_M ||
1098 output_csc == V4L2_COLORSPACE_470_SYSTEM_BG) {
1099 *r2y_table = csc_table->r2y_bt601_12_235; /* bt601 limit */
1100 } else {
1101 *r2y_table = csc_table->r2y_bt601; /* bt601 full */
1102 }
1103 }
1104 }
1105 } else {
1106 if (!is_input_yuv) {
1107 return 0;
1108 }
1109
1110 /*
1111 * is possible use bt2020 on rgb mode?
1112 */
1113 if (WARN_ON(output_csc == V4L2_COLORSPACE_BT2020)) {
1114 return -EINVAL;
1115 }
1116
1117 if (input_csc == V4L2_COLORSPACE_BT2020) {
1118 *y2r_table = csc_table->y2r_bt2020;
1119 } else if (input_csc == V4L2_COLORSPACE_REC709 || input_csc == V4L2_COLORSPACE_SMPTE240M ||
1120 input_csc == V4L2_COLORSPACE_DEFAULT) {
1121 *y2r_table = csc_table->y2r_bt709;
1122 } else if (input_csc == V4L2_COLORSPACE_SMPTE170M || input_csc == V4L2_COLORSPACE_470_SYSTEM_M ||
1123 input_csc == V4L2_COLORSPACE_470_SYSTEM_BG) {
1124 *y2r_table = csc_table->y2r_bt601_12_235; /* bt601 limit */
1125 } else {
1126 *y2r_table = csc_table->y2r_bt601; /* bt601 full */
1127 }
1128
1129 if (input_csc == V4L2_COLORSPACE_BT2020) {
1130 /*
1131 * We don't have bt601 to bt709 table, force use bt709.
1132 */
1133 *r2r_table = csc_table->r2r_bt2020_to_bt709;
1134 }
1135 }
1136
1137 return 0;
1138 }
1139
vop_setup_csc_mode(bool is_input_yuv,bool is_output_yuv,int input_csc,int output_csc,bool * y2r_en,bool * r2y_en,int * csc_mode)1140 static void vop_setup_csc_mode(bool is_input_yuv, bool is_output_yuv, int input_csc, int output_csc, bool *y2r_en,
1141 bool *r2y_en, int *csc_mode)
1142 {
1143 if (is_input_yuv && !is_output_yuv) {
1144 *y2r_en = true;
1145 *csc_mode = to_vop_csc_mode(input_csc);
1146 } else if (!is_input_yuv && is_output_yuv) {
1147 *r2y_en = true;
1148 *csc_mode = to_vop_csc_mode(output_csc);
1149 }
1150 }
1151
vop_csc_atomic_check(struct drm_crtc * crtc,struct drm_crtc_state * crtc_state)1152 static int vop_csc_atomic_check(struct drm_crtc *crtc, struct drm_crtc_state *crtc_state)
1153 {
1154 struct vop *vop = to_vop(crtc);
1155 struct drm_atomic_state *state = crtc_state->state;
1156 struct rockchip_crtc_state *s = to_rockchip_crtc_state(crtc_state);
1157 const struct vop_csc_table *csc_table = vop->data->csc_table;
1158 struct drm_plane_state *pstate;
1159 struct drm_plane *plane;
1160 bool is_input_yuv, is_output_yuv;
1161 int ret;
1162
1163 is_output_yuv = is_yuv_output(s->bus_format);
1164
1165 drm_atomic_crtc_state_for_each_plane(plane, crtc_state)
1166 {
1167 struct vop_plane_state *vop_plane_state;
1168 struct vop_win *win = to_vop_win(plane);
1169
1170 pstate = drm_atomic_get_plane_state(state, plane);
1171 if (IS_ERR(pstate)) {
1172 return PTR_ERR(pstate);
1173 }
1174 vop_plane_state = to_vop_plane_state(pstate);
1175
1176 if (!pstate->fb) {
1177 continue;
1178 }
1179 is_input_yuv = is_yuv_support(pstate->fb->format->format);
1180 vop_plane_state->y2r_en = false;
1181 vop_plane_state->r2r_en = false;
1182 vop_plane_state->r2y_en = false;
1183
1184 ret =
1185 vop_setup_csc_table(csc_table, is_input_yuv, is_output_yuv, vop_plane_state->color_space, s->color_space,
1186 &vop_plane_state->y2r_table, &vop_plane_state->r2r_table, &vop_plane_state->r2y_table);
1187 if (ret) {
1188 return ret;
1189 }
1190
1191 vop_setup_csc_mode(is_input_yuv, s->yuv_overlay, vop_plane_state->color_space, s->color_space,
1192 &vop_plane_state->y2r_en, &vop_plane_state->r2y_en, &vop_plane_state->csc_mode);
1193
1194 if (csc_table) {
1195 vop_plane_state->y2r_en = !!vop_plane_state->y2r_table;
1196 vop_plane_state->r2r_en = !!vop_plane_state->r2r_table;
1197 vop_plane_state->r2y_en = !!vop_plane_state->r2y_table;
1198 continue;
1199 }
1200
1201 /*
1202 * This is update for IC design not reasonable, when enable
1203 * hdr2sdr on rk3328, vop can't support per-pixel alpha * global
1204 * alpha,so we must back to gpu, but gpu can't support hdr2sdr,
1205 * gpu output hdr UI, vop will do:
1206 * UI(rgbx) -> yuv -> rgb ->hdr2sdr -> overlay -> output.
1207 */
1208 if (s->hdr.hdr2sdr_en && vop_plane_state->eotf == HDMI_EOTF_SMPTE_ST2084 &&
1209 !is_yuv_support(pstate->fb->format->format)) {
1210 vop_plane_state->r2y_en = true;
1211 }
1212 if (win->feature & WIN_FEATURE_PRE_OVERLAY) {
1213 vop_plane_state->r2r_en = s->hdr.sdr2hdr_state.rgb2rgb_pre_conv_en;
1214 } else if (win->feature & WIN_FEATURE_HDR2SDR) {
1215 vop_plane_state->r2r_en = s->hdr.sdr2hdr_state.rgb2rgb_post_conv_en;
1216 }
1217 }
1218
1219 return 0;
1220 }
1221
vop_enable_debug_irq(struct drm_crtc * crtc)1222 static void vop_enable_debug_irq(struct drm_crtc *crtc)
1223 {
1224 struct vop *vop = to_vop(crtc);
1225 uint32_t irqs;
1226
1227 irqs = BUS_ERROR_INTR | WIN0_EMPTY_INTR | WIN1_EMPTY_INTR | WIN2_EMPTY_INTR | WIN3_EMPTY_INTR | HWC_EMPTY_INTR |
1228 POST_BUF_EMPTY_INTR;
1229 VOP_INTR_SET_TYPE(vop, clear, irqs, 1);
1230 VOP_INTR_SET_TYPE(vop, enable, irqs, 1);
1231 }
1232
vop_dsp_hold_valid_irq_enable(struct vop * vop)1233 static void vop_dsp_hold_valid_irq_enable(struct vop *vop)
1234 {
1235 unsigned long flags;
1236
1237 if (WARN_ON(!vop->is_enabled)) {
1238 return;
1239 }
1240
1241 spin_lock_irqsave(&vop->irq_lock, flags);
1242
1243 VOP_INTR_SET_TYPE(vop, clear, DSP_HOLD_VALID_INTR, 1);
1244 VOP_INTR_SET_TYPE(vop, enable, DSP_HOLD_VALID_INTR, 1);
1245
1246 spin_unlock_irqrestore(&vop->irq_lock, flags);
1247 }
1248
vop_dsp_hold_valid_irq_disable(struct vop * vop)1249 static void vop_dsp_hold_valid_irq_disable(struct vop *vop)
1250 {
1251 unsigned long flags;
1252
1253 if (WARN_ON(!vop->is_enabled)) {
1254 return;
1255 }
1256
1257 spin_lock_irqsave(&vop->irq_lock, flags);
1258
1259 VOP_INTR_SET_TYPE(vop, enable, DSP_HOLD_VALID_INTR, 0);
1260
1261 spin_unlock_irqrestore(&vop->irq_lock, flags);
1262 }
1263
1264 /*
1265 * (1) each frame starts at the start of the Vsync pulse which is signaled by
1266 * the "FRAME_SYNC" interrupt.
1267 * (2) the active data region of each frame ends at dsp_vact_end
1268 * (3) we should program this same number (dsp_vact_end) into dsp_line_frag_num,
1269 * to get "LINE_FLAG" interrupt at the end of the active on screen data.
1270 *
1271 * VOP_INTR_CTRL0.dsp_line_frag_num = VOP_DSP_VACT_ST_END.dsp_vact_end
1272 * Interrupts
1273 * LINE_FLAG -------------------------------+
1274 * FRAME_SYNC ----+ |
1275 * | |
1276 * v v
1277 * | Vsync | Vbp | Vactive | Vfp |
1278 * ^ ^ ^ ^
1279 * | | | |
1280 * | | | |
1281 * dsp_vs_end ------------+ | | | VOP_DSP_VTOTAL_VS_END
1282 * dsp_vact_start --------------+ | | VOP_DSP_VACT_ST_END
1283 * dsp_vact_end ----------------------------+ | VOP_DSP_VACT_ST_END
1284 * dsp_total -------------------------------------+ VOP_DSP_VTOTAL_VS_END
1285 */
vop_line_flag_irq_is_enabled(struct vop * vop)1286 static bool vop_line_flag_irq_is_enabled(struct vop *vop)
1287 {
1288 uint32_t line_flag_irq;
1289 unsigned long flags;
1290
1291 spin_lock_irqsave(&vop->irq_lock, flags);
1292
1293 line_flag_irq = VOP_INTR_GET_TYPE(vop, enable, LINE_FLAG_INTR);
1294
1295 spin_unlock_irqrestore(&vop->irq_lock, flags);
1296
1297 return !!line_flag_irq;
1298 }
1299
vop_line_flag_irq_enable(struct vop * vop)1300 static void vop_line_flag_irq_enable(struct vop *vop)
1301 {
1302 unsigned long flags;
1303
1304 if (WARN_ON(!vop->is_enabled)) {
1305 return;
1306 }
1307
1308 spin_lock_irqsave(&vop->irq_lock, flags);
1309
1310 VOP_INTR_SET_TYPE(vop, clear, LINE_FLAG_INTR, 1);
1311 VOP_INTR_SET_TYPE(vop, enable, LINE_FLAG_INTR, 1);
1312
1313 spin_unlock_irqrestore(&vop->irq_lock, flags);
1314 }
1315
vop_line_flag_irq_disable(struct vop * vop)1316 static void vop_line_flag_irq_disable(struct vop *vop)
1317 {
1318 unsigned long flags;
1319
1320 if (WARN_ON(!vop->is_enabled)) {
1321 return;
1322 }
1323
1324 spin_lock_irqsave(&vop->irq_lock, flags);
1325
1326 VOP_INTR_SET_TYPE(vop, enable, LINE_FLAG_INTR, 0);
1327
1328 spin_unlock_irqrestore(&vop->irq_lock, flags);
1329 }
1330
vop_core_clks_enable(struct vop * vop)1331 static int vop_core_clks_enable(struct vop *vop)
1332 {
1333 int ret;
1334
1335 ret = clk_enable(vop->hclk);
1336 if (ret < 0) {
1337 return ret;
1338 }
1339
1340 ret = clk_enable(vop->aclk);
1341 if (ret < 0) {
1342 goto err_disable_hclk;
1343 }
1344
1345 return 0;
1346
1347 err_disable_hclk:
1348 clk_disable(vop->hclk);
1349 return ret;
1350 }
1351
vop_core_clks_disable(struct vop * vop)1352 static void vop_core_clks_disable(struct vop *vop)
1353 {
1354 clk_disable(vop->aclk);
1355 clk_disable(vop->hclk);
1356 }
1357
vop_crtc_load_lut(struct drm_crtc * crtc)1358 static void vop_crtc_load_lut(struct drm_crtc *crtc)
1359 {
1360 struct vop *vop = to_vop(crtc);
1361 int i, dle, lut_idx = 0;
1362
1363 if (!vop->is_enabled || !vop->lut || !vop->lut_regs) {
1364 return;
1365 }
1366
1367 if (WARN_ON(!drm_modeset_is_locked(&crtc->mutex))) {
1368 return;
1369 }
1370
1371 if (!VOP_CTRL_SUPPORT(vop, update_gamma_lut)) {
1372 spin_lock(&vop->reg_lock);
1373 VOP_CTRL_SET(vop, dsp_lut_en, 0);
1374 vop_cfg_done(vop);
1375 spin_unlock(&vop->reg_lock);
1376
1377 #define CTRL_GET(name) VOP_CTRL_GET(vop, name)
1378 readx_poll_timeout(CTRL_GET, dsp_lut_en, dle, !dle, 0x5, 0x8235);
1379 } else {
1380 lut_idx = CTRL_GET(lut_buffer_index);
1381 }
1382
1383 for (i = 0; i < vop->lut_len; i++) {
1384 vop_write_lut(vop, i << 0x2, vop->lut[i]);
1385 }
1386
1387 spin_lock(&vop->reg_lock);
1388
1389 VOP_CTRL_SET(vop, dsp_lut_en, 1);
1390 VOP_CTRL_SET(vop, update_gamma_lut, 1);
1391 vop_cfg_done(vop);
1392 vop->lut_active = true;
1393
1394 spin_unlock(&vop->reg_lock);
1395
1396 if (VOP_CTRL_SUPPORT(vop, update_gamma_lut)) {
1397 readx_poll_timeout(CTRL_GET, lut_buffer_index, dle, dle != lut_idx, 0x5, 0x8235);
1398 /*
1399 * update_gamma value auto clean to 0 by HW, should not
1400 * bakeup it.
1401 */
1402 VOP_CTRL_SET(vop, update_gamma_lut, 0);
1403 }
1404 #undef CTRL_GET
1405 }
1406
rockchip_vop_crtc_fb_gamma_set(struct drm_crtc * crtc,u16 red,u16 green,u16 blue,int regno)1407 static void rockchip_vop_crtc_fb_gamma_set(struct drm_crtc *crtc, u16 red, u16 green, u16 blue, int regno)
1408 {
1409 struct vop *vop = to_vop(crtc);
1410 u32 lut_len = vop->lut_len;
1411 u32 r, g, b;
1412
1413 if (regno >= lut_len || !vop->lut) {
1414 return;
1415 }
1416
1417 r = red * (lut_len - 1) / 0xffff;
1418 g = green * (lut_len - 1) / 0xffff;
1419 b = blue * (lut_len - 1) / 0xffff;
1420 vop->lut[regno] = r * lut_len * lut_len + g * lut_len + b;
1421 }
1422
rockchip_vop_crtc_fb_gamma_get(struct drm_crtc * crtc,u16 * red,u16 * green,u16 * blue,int regno)1423 static void rockchip_vop_crtc_fb_gamma_get(struct drm_crtc *crtc, u16 *red, u16 *green, u16 *blue, int regno)
1424 {
1425 struct vop *vop = to_vop(crtc);
1426 u32 lut_len = vop->lut_len;
1427 u32 r, g, b;
1428
1429 if (regno >= lut_len || !vop->lut) {
1430 return;
1431 }
1432
1433 r = (vop->lut[regno] / lut_len / lut_len) & (lut_len - 1);
1434 g = (vop->lut[regno] / lut_len) & (lut_len - 1);
1435 b = vop->lut[regno] & (lut_len - 1);
1436 *red = r * 0xffff / (lut_len - 1);
1437 *green = g * 0xffff / (lut_len - 1);
1438 *blue = b * 0xffff / (lut_len - 1);
1439 }
1440
vop_crtc_legacy_gamma_set(struct drm_crtc * crtc,u16 * red,u16 * green,u16 * blue,uint32_t size,struct drm_modeset_acquire_ctx * ctx)1441 static int vop_crtc_legacy_gamma_set(struct drm_crtc *crtc, u16 *red, u16 *green, u16 *blue, uint32_t size,
1442 struct drm_modeset_acquire_ctx *ctx)
1443 {
1444 struct vop *vop = to_vop(crtc);
1445 int len = min(size, vop->lut_len);
1446 int i;
1447
1448 if (!vop->lut) {
1449 return -EINVAL;
1450 }
1451
1452 for (i = 0; i < len; i++) {
1453 rockchip_vop_crtc_fb_gamma_set(crtc, red[i], green[i], blue[i], i);
1454 }
1455
1456 vop_crtc_load_lut(crtc);
1457
1458 return 0;
1459 }
1460
vop_crtc_atomic_gamma_set(struct drm_crtc * crtc,struct drm_crtc_state * old_state)1461 static int vop_crtc_atomic_gamma_set(struct drm_crtc *crtc, struct drm_crtc_state *old_state)
1462 {
1463 struct vop *vop = to_vop(crtc);
1464 struct drm_color_lut *lut = vop->gamma_lut;
1465 unsigned int i;
1466
1467 for (i = 0; i < vop->lut_len; i++) {
1468 rockchip_vop_crtc_fb_gamma_set(crtc, lut[i].red, lut[i].green, lut[i].blue, i);
1469 }
1470 vop_crtc_load_lut(crtc);
1471
1472 return 0;
1473 }
1474
vop_power_enable(struct drm_crtc * crtc)1475 static void vop_power_enable(struct drm_crtc *crtc)
1476 {
1477 struct vop *vop = to_vop(crtc);
1478 int ret;
1479
1480 ret = clk_prepare_enable(vop->hclk);
1481 if (ret < 0) {
1482 dev_err(vop->dev, "failed to enable hclk - %d\n", ret);
1483 return;
1484 }
1485
1486 ret = clk_prepare_enable(vop->dclk);
1487 if (ret < 0) {
1488 dev_err(vop->dev, "failed to enable dclk - %d\n", ret);
1489 goto err_disable_hclk;
1490 }
1491
1492 ret = clk_prepare_enable(vop->aclk);
1493 if (ret < 0) {
1494 dev_err(vop->dev, "failed to enable aclk - %d\n", ret);
1495 goto err_disable_dclk;
1496 }
1497
1498 ret = pm_runtime_get_sync(vop->dev);
1499 if (ret < 0) {
1500 dev_err(vop->dev, "failed to get pm runtime: %d\n", ret);
1501 return;
1502 }
1503
1504 memcpy(vop->regsbak, vop->regs, vop->len);
1505
1506 if (VOP_CTRL_SUPPORT(vop, version)) {
1507 uint32_t version = VOP_CTRL_GET(vop, version);
1508 /*
1509 * Fixup rk3288w version.
1510 */
1511 if (version && version == 0x0a05) {
1512 vop->version = VOP_VERSION(0x3, 1);
1513 }
1514 }
1515
1516 vop->is_enabled = true;
1517
1518 return;
1519
1520 err_disable_dclk:
1521 clk_disable_unprepare(vop->dclk);
1522 err_disable_hclk:
1523 clk_disable_unprepare(vop->hclk);
1524 }
1525
vop_initial(struct drm_crtc * crtc)1526 static void vop_initial(struct drm_crtc *crtc)
1527 {
1528 struct vop *vop = to_vop(crtc);
1529 int i;
1530
1531 vop_power_enable(crtc);
1532
1533 VOP_CTRL_SET(vop, global_regdone_en, 1);
1534 VOP_CTRL_SET(vop, dsp_blank, 0);
1535 VOP_CTRL_SET(vop, axi_outstanding_max_num, 0x1e);
1536 VOP_CTRL_SET(vop, axi_max_outstanding_en, 1);
1537 VOP_CTRL_SET(vop, dither_up_en, 1);
1538
1539 /*
1540 * We need to make sure that all windows are disabled before resume
1541 * the crtc. Otherwise we might try to scan from a destroyed
1542 * buffer later.
1543 */
1544 for (i = 0; i < vop->num_wins; i++) {
1545 struct vop_win *win = &vop->win[i];
1546 int channel = i * 0x2 + 1;
1547
1548 VOP_WIN_SET(vop, win, channel, ((channel + 1) << 0x4) | channel);
1549 }
1550 VOP_CTRL_SET(vop, afbdc_en, 0);
1551 vop_enable_debug_irq(crtc);
1552 }
1553
vop_crtc_atomic_disable(struct drm_crtc * crtc,struct drm_crtc_state * old_state)1554 static void vop_crtc_atomic_disable(struct drm_crtc *crtc, struct drm_crtc_state *old_state)
1555 {
1556 struct vop *vop = to_vop(crtc);
1557 int sys_status = drm_crtc_index(crtc) ? SYS_STATUS_LCDC1 : SYS_STATUS_LCDC0;
1558
1559 WARN_ON(vop->event);
1560
1561 vop_lock(vop);
1562 VOP_CTRL_SET(vop, reg_done_frm, 1);
1563 VOP_CTRL_SET(vop, dsp_interlace, 0);
1564 drm_crtc_vblank_off(crtc);
1565 VOP_CTRL_SET(vop, out_mode, ROCKCHIP_OUT_MODE_P888);
1566 VOP_CTRL_SET(vop, afbdc_en, 0);
1567 vop_disable_all_planes(vop);
1568
1569 /*
1570 * Vop standby will take effect at end of current frame,
1571 * if dsp hold valid irq happen, it means standby complete.
1572 *
1573 * we must wait standby complete when we want to disable aclk,
1574 * if not, memory bus maybe dead.
1575 */
1576 reinit_completion(&vop->dsp_hold_completion);
1577 vop_dsp_hold_valid_irq_enable(vop);
1578
1579 spin_lock(&vop->reg_lock);
1580
1581 VOP_CTRL_SET(vop, standby, 1);
1582
1583 spin_unlock(&vop->reg_lock);
1584
1585 WARN_ON(!wait_for_completion_timeout(&vop->dsp_hold_completion, msecs_to_jiffies(0x32)));
1586
1587 vop_dsp_hold_valid_irq_disable(vop);
1588
1589 vop->is_enabled = false;
1590 if (vop->is_iommu_enabled) {
1591 /*
1592 * vop standby complete, so iommu detach is safe.
1593 */
1594 VOP_CTRL_SET(vop, dma_stop, 1);
1595 rockchip_drm_dma_detach_device(vop->drm_dev, vop->dev);
1596 vop->is_iommu_enabled = false;
1597 }
1598
1599 pm_runtime_put_sync(vop->dev);
1600 clk_disable_unprepare(vop->dclk);
1601 clk_disable_unprepare(vop->aclk);
1602 clk_disable_unprepare(vop->hclk);
1603 vop_unlock(vop);
1604
1605 rockchip_clear_system_status(sys_status);
1606
1607 if (crtc->state->event && !crtc->state->active) {
1608 spin_lock_irq(&crtc->dev->event_lock);
1609 drm_crtc_send_vblank_event(crtc, crtc->state->event);
1610 spin_unlock_irq(&crtc->dev->event_lock);
1611
1612 crtc->state->event = NULL;
1613 }
1614 }
1615
vop_plane_prepare_fb(struct drm_plane * plane,struct drm_plane_state * new_state)1616 static int vop_plane_prepare_fb(struct drm_plane *plane, struct drm_plane_state *new_state)
1617 {
1618 if (plane->state->fb) {
1619 drm_framebuffer_get(plane->state->fb);
1620 }
1621
1622 return 0;
1623 }
1624
vop_plane_cleanup_fb(struct drm_plane * plane,struct drm_plane_state * old_state)1625 static void vop_plane_cleanup_fb(struct drm_plane *plane, struct drm_plane_state *old_state)
1626 {
1627 if (old_state->fb) {
1628 drm_framebuffer_put(old_state->fb);
1629 }
1630 }
1631
vop_plane_atomic_check(struct drm_plane * plane,struct drm_plane_state * state)1632 static int vop_plane_atomic_check(struct drm_plane *plane, struct drm_plane_state *state)
1633 {
1634 struct drm_crtc *crtc = state->crtc;
1635 struct drm_crtc_state *crtc_state;
1636 struct drm_framebuffer *fb = state->fb;
1637 struct vop_win *win = to_vop_win(plane);
1638 struct vop_plane_state *vop_plane_state = to_vop_plane_state(state);
1639 const struct vop_data *vop_data;
1640 struct vop *vop;
1641 int ret;
1642 struct drm_rect *dest = &vop_plane_state->dest;
1643 struct drm_rect *src = &vop_plane_state->src;
1644 struct drm_gem_object *obj, *uv_obj;
1645 struct rockchip_gem_object *rk_obj, *rk_uv_obj;
1646 int min_scale = win->phy->scl ? FRAC_16_16(1, 0x8) : DRM_PLANE_HELPER_NO_SCALING;
1647 int max_scale = win->phy->scl ? FRAC_16_16(0x8, 1) : DRM_PLANE_HELPER_NO_SCALING;
1648 unsigned long offset;
1649 dma_addr_t dma_addr;
1650
1651 crtc = crtc ? crtc : plane->state->crtc;
1652 if (!crtc || !fb) {
1653 plane->state->visible = false;
1654 return 0;
1655 }
1656
1657 crtc_state = drm_atomic_get_existing_crtc_state(state->state, crtc);
1658 if (WARN_ON(!crtc_state)) {
1659 return -EINVAL;
1660 }
1661
1662 src->x1 = state->src_x;
1663 src->y1 = state->src_y;
1664 src->x2 = state->src_x + state->src_w;
1665 src->y2 = state->src_y + state->src_h;
1666 dest->x1 = state->crtc_x;
1667 dest->y1 = state->crtc_y;
1668 dest->x2 = state->crtc_x + state->crtc_w;
1669 dest->y2 = state->crtc_y + state->crtc_h;
1670 vop_plane_state->zpos = state->zpos;
1671 vop_plane_state->blend_mode = state->pixel_blend_mode;
1672
1673 ret = drm_atomic_helper_check_plane_state(state, crtc_state, min_scale, max_scale, true, true);
1674 if (ret) {
1675 return ret;
1676 }
1677
1678 if (!state->visible) {
1679 return 0;
1680 }
1681
1682 vop_plane_state->format = vop_convert_format(fb->format->format);
1683 if (vop_plane_state->format < 0) {
1684 return vop_plane_state->format;
1685 }
1686
1687 vop = to_vop(crtc);
1688 vop_data = vop->data;
1689
1690 if (state->src_w >> 0x10 < 0x4 || state->src_h >> 0x10 < 0x4 || state->crtc_w < 0x4 || state->crtc_h < 0x4) {
1691 DRM_ERROR("Invalid size: %dx%d->%dx%d, min size is 4x4\n", state->src_w >> 0x10, state->src_h >> 0x10,
1692 state->crtc_w, state->crtc_h);
1693 return -EINVAL;
1694 }
1695
1696 if (((drm_rect_width(src) >> 0x10) > vop_data->max_input.width) ||
1697 ((drm_rect_height(src) >> 0x10) > vop_data->max_input.height)) {
1698 DRM_ERROR("Invalid source: %dx%d. max input: %dx%d\n", drm_rect_width(src) >> 0x10,
1699 drm_rect_height(src) >> 0x10, vop_data->max_input.width, vop_data->max_input.height);
1700 return -EINVAL;
1701 }
1702
1703 /*
1704 * Src.x1 can be odd when do clip, but yuv plane start point
1705 * need align with 2 pixel.
1706 */
1707 if (fb->format->is_yuv && ((state->src.x1 >> 0x10) % 0x2)) {
1708 DRM_ERROR("Invalid Source: Yuv format not support odd xpos\n");
1709 return -EINVAL;
1710 }
1711
1712 if (fb->format->is_yuv && (state->rotation & DRM_MODE_REFLECT_Y)) {
1713 DRM_ERROR("Invalid Source: Yuv format does not support this rotation\n");
1714 return -EINVAL;
1715 }
1716
1717 offset = (src->x1 >> 0x10) * fb->format->cpp[0];
1718 vop_plane_state->offset = offset + fb->offsets[0];
1719 if (state->rotation & DRM_MODE_REFLECT_Y) {
1720 offset += ((src->y2 >> 0x10) - 1) * fb->pitches[0];
1721 } else {
1722 offset += (src->y1 >> 0x10) * fb->pitches[0];
1723 }
1724
1725 obj = fb->obj[0];
1726 rk_obj = to_rockchip_obj(obj);
1727 vop_plane_state->yrgb_mst = rk_obj->dma_addr + offset + fb->offsets[0];
1728 if (fb->format->is_yuv) {
1729 int hsub = fb->format->hsub;
1730 int vsub = fb->format->vsub;
1731
1732 offset = (src->x1 >> 0x10) * fb->format->cpp[1] / hsub;
1733 offset += (src->y1 >> 0x10) * fb->pitches[1] / vsub;
1734
1735 uv_obj = fb->obj[1];
1736 rk_uv_obj = to_rockchip_obj(uv_obj);
1737
1738 dma_addr = rk_uv_obj->dma_addr + offset + fb->offsets[1];
1739 vop_plane_state->uv_mst = dma_addr;
1740 }
1741
1742 return 0;
1743 }
1744
vop_plane_atomic_disable(struct drm_plane * plane,struct drm_plane_state * old_state)1745 static void vop_plane_atomic_disable(struct drm_plane *plane, struct drm_plane_state *old_state)
1746 {
1747 struct vop_win *win = to_vop_win(plane);
1748 struct vop *vop = to_vop(old_state->crtc);
1749 #if defined(CONFIG_ROCKCHIP_DRM_DEBUG)
1750 struct vop_plane_state *vop_plane_state = to_vop_plane_state(plane->state);
1751 #endif
1752
1753 if (!old_state->crtc) {
1754 return;
1755 }
1756
1757 spin_lock(&vop->reg_lock);
1758
1759 vop_win_disable(vop, win);
1760
1761 /*
1762 * IC design bug: in the bandwidth tension environment when close win2,
1763 * vop will access the freed memory lead to iommu pagefault.
1764 * so we add this reset to workaround.
1765 */
1766 if (VOP_MAJOR(vop->version) == 0x2 && VOP_MINOR(vop->version) == 0x5 && win->win_id == 0x2) {
1767 VOP_WIN_SET(vop, win, yrgb_mst, 0);
1768 }
1769
1770 #if defined(CONFIG_ROCKCHIP_DRM_DEBUG)
1771 kfree(vop_plane_state->planlist);
1772 vop_plane_state->planlist = NULL;
1773 #endif
1774
1775 spin_unlock(&vop->reg_lock);
1776 }
1777
vop_plane_atomic_update(struct drm_plane * plane,struct drm_plane_state * old_state)1778 static void vop_plane_atomic_update(struct drm_plane *plane, struct drm_plane_state *old_state)
1779 {
1780 struct drm_plane_state *state = plane->state;
1781 struct drm_crtc *crtc = state->crtc;
1782 struct drm_display_mode *mode = NULL;
1783 struct vop_win *win = to_vop_win(plane);
1784 struct vop_plane_state *vop_plane_state = to_vop_plane_state(state);
1785 struct drm_display_mode *adjusted_mode = &crtc->state->adjusted_mode;
1786 struct rockchip_crtc_state *s;
1787 struct vop *vop = to_vop(state->crtc);
1788 struct drm_framebuffer *fb = state->fb;
1789 unsigned int actual_w, actual_h, dsp_w, dsp_h;
1790 unsigned int dsp_stx, dsp_sty;
1791 uint32_t act_info, dsp_info, dsp_st;
1792 struct drm_rect *src = &vop_plane_state->src;
1793 struct drm_rect *dest = &vop_plane_state->dest;
1794 const uint32_t *y2r_table = vop_plane_state->y2r_table;
1795 const uint32_t *r2r_table = vop_plane_state->r2r_table;
1796 const uint32_t *r2y_table = vop_plane_state->r2y_table;
1797 uint32_t val;
1798 bool rb_swap, global_alpha_en;
1799 int is_yuv = fb->format->is_yuv;
1800
1801 #if defined(CONFIG_ROCKCHIP_DRM_DEBUG)
1802 bool AFBC_flag = false;
1803 struct vop_dump_list *planlist;
1804 unsigned long num_pages;
1805 struct page **pages;
1806 struct drm_gem_object *obj;
1807 struct rockchip_gem_object *rk_obj;
1808
1809 num_pages = 0;
1810 pages = NULL;
1811 obj = fb->obj[0];
1812 rk_obj = to_rockchip_obj(obj);
1813 if (rk_obj) {
1814 num_pages = rk_obj->num_pages;
1815 pages = rk_obj->pages;
1816 }
1817 if (fb->modifier == DRM_FORMAT_MOD_ARM_AFBC(AFBC_FORMAT_MOD_BLOCK_SIZE_16x16)) {
1818 AFBC_flag = true;
1819 } else {
1820 AFBC_flag = false;
1821 }
1822 #endif
1823
1824 /*
1825 * can't update plane when vop is disabled.
1826 */
1827 if (WARN_ON(!crtc)) {
1828 return;
1829 }
1830
1831 if (WARN_ON(!vop->is_enabled)) {
1832 return;
1833 }
1834
1835 if (!state->visible) {
1836 vop_plane_atomic_disable(plane, old_state);
1837 return;
1838 }
1839
1840 mode = &crtc->state->adjusted_mode;
1841 actual_w = drm_rect_width(src) >> 0x10;
1842 actual_h = drm_rect_height(src) >> 0x10;
1843
1844 dsp_w = drm_rect_width(dest);
1845 if (dest->x1 + dsp_w > adjusted_mode->hdisplay) {
1846 DRM_ERROR("%s win%d dest->x1[%d] + dsp_w[%d] exceed mode hdisplay[%d]\n", crtc->name, win->win_id, dest->x1,
1847 dsp_w, adjusted_mode->hdisplay);
1848 dsp_w = adjusted_mode->hdisplay - dest->x1;
1849 if (dsp_w < 0x4) {
1850 dsp_w = 0x4;
1851 }
1852 actual_w = dsp_w * actual_w / drm_rect_width(dest);
1853 }
1854 dsp_h = drm_rect_height(dest);
1855 if (dest->y1 + dsp_h > adjusted_mode->vdisplay) {
1856 DRM_ERROR("%s win%d dest->y1[%d] + dsp_h[%d] exceed mode vdisplay[%d]\n", crtc->name, win->win_id, dest->y1,
1857 dsp_h, adjusted_mode->vdisplay);
1858 dsp_h = adjusted_mode->vdisplay - dest->y1;
1859 if (dsp_h < 0x4) {
1860 dsp_h = 0x4;
1861 }
1862 actual_h = dsp_h * actual_h / drm_rect_height(dest);
1863 }
1864
1865 act_info = ((actual_h - 1) << 0x10) | ((actual_w - 1) & 0xffff);
1866
1867 dsp_info = (dsp_h - 1) << 0x10;
1868 dsp_info |= (dsp_w - 1) & 0xffff;
1869
1870 dsp_stx = dest->x1 + mode->crtc_htotal - mode->crtc_hsync_start;
1871 dsp_sty = dest->y1 + mode->crtc_vtotal - mode->crtc_vsync_start;
1872 dsp_st = (dsp_sty << 0x10) | (dsp_stx & 0xffff);
1873
1874 s = to_rockchip_crtc_state(crtc->state);
1875 spin_lock(&vop->reg_lock);
1876
1877 VOP_WIN_SET(vop, win, format, vop_plane_state->format);
1878 VOP_WIN_SET(vop, win, yrgb_vir, DIV_ROUND_UP(fb->pitches[0], 0x4));
1879 VOP_WIN_SET(vop, win, yrgb_mst, vop_plane_state->yrgb_mst);
1880
1881 VOP_WIN_SET(vop, win, ymirror, (state->rotation & DRM_MODE_REFLECT_Y) ? 1 : 0);
1882 VOP_WIN_SET(vop, win, xmirror, (state->rotation & DRM_MODE_REFLECT_X) ? 1 : 0);
1883
1884 if (is_yuv) {
1885 VOP_WIN_SET(vop, win, uv_vir, DIV_ROUND_UP(fb->pitches[1], 0x4));
1886 VOP_WIN_SET(vop, win, uv_mst, vop_plane_state->uv_mst);
1887 }
1888 VOP_WIN_SET(vop, win, fmt_10, is_yuv_10bit(fb->format->format));
1889 VOP_WIN_SET(vop, win, fmt_yuyv, is_yuyv_format(fb->format->format));
1890
1891 if (win->phy->scl) {
1892 scl_vop_cal_scl_fac(vop, win, actual_w, actual_h, drm_rect_width(dest), drm_rect_height(dest),
1893 fb->format->format);
1894 }
1895
1896 VOP_WIN_SET(vop, win, act_info, act_info);
1897 VOP_WIN_SET(vop, win, dsp_info, dsp_info);
1898 VOP_WIN_SET(vop, win, dsp_st, dsp_st);
1899
1900 rb_swap = has_rb_swapped(fb->format->format);
1901 /*
1902 * VOP full need to do rb swap to show rgb888/bgr888 format color correctly
1903 */
1904 if ((fb->format->format == DRM_FORMAT_RGB888 || fb->format->format == DRM_FORMAT_BGR888) &&
1905 VOP_MAJOR(vop->version) == 0x3) {
1906 rb_swap = !rb_swap;
1907 }
1908 VOP_WIN_SET(vop, win, rb_swap, rb_swap);
1909
1910 global_alpha_en = (vop_plane_state->global_alpha == 0xff) ? 0 : 1;
1911 if ((is_alpha_support(fb->format->format) || global_alpha_en) && (s->dsp_layer_sel & 0x3) != win->win_id) {
1912 int src_blend_m0;
1913
1914 if (is_alpha_support(fb->format->format) && global_alpha_en) {
1915 src_blend_m0 = ALPHA_PER_PIX_GLOBAL;
1916 } else if (is_alpha_support(fb->format->format)) {
1917 src_blend_m0 = ALPHA_PER_PIX;
1918 } else {
1919 src_blend_m0 = ALPHA_GLOBAL;
1920 }
1921
1922 VOP_WIN_SET(vop, win, dst_alpha_ctl, DST_FACTOR_M0(ALPHA_SRC_INVERSE));
1923 val = SRC_ALPHA_EN(1) | SRC_COLOR_M0(ALPHA_SRC_PRE_MUL) | SRC_ALPHA_M0(ALPHA_STRAIGHT) |
1924 SRC_BLEND_M0(src_blend_m0) | SRC_ALPHA_CAL_M0(ALPHA_SATURATION) |
1925 SRC_FACTOR_M0(global_alpha_en ? ALPHA_SRC_GLOBAL : ALPHA_ONE);
1926 VOP_WIN_SET(vop, win, src_alpha_ctl, val);
1927 VOP_WIN_SET(vop, win, alpha_pre_mul, vop_plane_state->blend_mode == DRM_MODE_BLEND_PREMULTI ? 1 : 0);
1928 VOP_WIN_SET(vop, win, alpha_mode, 1);
1929 VOP_WIN_SET(vop, win, alpha_en, 1);
1930 } else {
1931 VOP_WIN_SET(vop, win, src_alpha_ctl, SRC_ALPHA_EN(0));
1932 VOP_WIN_SET(vop, win, alpha_en, 0);
1933 }
1934 VOP_WIN_SET(vop, win, global_alpha_val, vop_plane_state->global_alpha);
1935
1936 VOP_WIN_SET(vop, win, csc_mode, vop_plane_state->csc_mode);
1937 if (win->csc) {
1938 vop_load_csc_table(vop, win->csc->y2r_offset, y2r_table);
1939 vop_load_csc_table(vop, win->csc->r2r_offset, r2r_table);
1940 vop_load_csc_table(vop, win->csc->r2y_offset, r2y_table);
1941 VOP_WIN_SET_EXT(vop, win, csc, y2r_en, vop_plane_state->y2r_en);
1942 VOP_WIN_SET_EXT(vop, win, csc, r2r_en, vop_plane_state->r2r_en);
1943 VOP_WIN_SET_EXT(vop, win, csc, r2y_en, vop_plane_state->r2y_en);
1944 VOP_WIN_SET_EXT(vop, win, csc, csc_mode, vop_plane_state->csc_mode);
1945 }
1946 VOP_WIN_SET(vop, win, enable, 1);
1947 VOP_WIN_SET(vop, win, gate, 1);
1948 spin_unlock(&vop->reg_lock);
1949 /*
1950 * spi interface(vop_plane_state->yrgb_kvaddr, fb->pixel_format,
1951 * actual_w, actual_h)
1952 */
1953 vop->is_iommu_needed = true;
1954 #if defined(CONFIG_ROCKCHIP_DRM_DEBUG)
1955 kfree(vop_plane_state->planlist);
1956 vop_plane_state->planlist = NULL;
1957
1958 planlist = kmalloc(sizeof(*planlist), GFP_KERNEL);
1959 if (planlist) {
1960 planlist->dump_info.AFBC_flag = AFBC_flag;
1961 planlist->dump_info.area_id = win->area_id;
1962 planlist->dump_info.win_id = win->win_id;
1963 planlist->dump_info.yuv_format = is_yuv_support(fb->format->format);
1964 planlist->dump_info.num_pages = num_pages;
1965 planlist->dump_info.pages = pages;
1966 planlist->dump_info.offset = vop_plane_state->offset;
1967 planlist->dump_info.pitches = fb->pitches[0];
1968 planlist->dump_info.height = actual_h;
1969 planlist->dump_info.format = fb->format;
1970 list_add_tail(&planlist->entry, &vop->rockchip_crtc.vop_dump_list_head);
1971 vop_plane_state->planlist = planlist;
1972 } else {
1973 DRM_ERROR("can't alloc a node of planlist %p\n", planlist);
1974 return;
1975 }
1976 if (vop->rockchip_crtc.vop_dump_status == DUMP_KEEP || vop->rockchip_crtc.vop_dump_times > 0) {
1977 rockchip_drm_dump_plane_buffer(&planlist->dump_info, vop->rockchip_crtc.frame_count);
1978 vop->rockchip_crtc.vop_dump_times--;
1979 }
1980 #endif
1981 }
1982
1983 static const struct drm_plane_helper_funcs plane_helper_funcs = {
1984 .prepare_fb = vop_plane_prepare_fb,
1985 .cleanup_fb = vop_plane_cleanup_fb,
1986 .atomic_check = vop_plane_atomic_check,
1987 .atomic_update = vop_plane_atomic_update,
1988 .atomic_disable = vop_plane_atomic_disable,
1989 };
1990
1991 /**
1992 * rockchip_atomic_helper_update_plane copy from drm_atomic_helper_update_plane
1993 * be designed to support async commit at ioctl DRM_IOCTL_MODE_SETPLANE.
1994 * @plane: plane object to update
1995 * @crtc: owning CRTC of owning plane
1996 * @fb: framebuffer to flip onto plane
1997 * @crtc_x: x offset of primary plane on crtc
1998 * @crtc_y: y offset of primary plane on crtc
1999 * @crtc_w: width of primary plane rectangle on crtc
2000 * @crtc_h: height of primary plane rectangle on crtc
2001 * @src_x: x offset of @fb for panning
2002 * @src_y: y offset of @fb for panning
2003 * @src_w: width of source rectangle in @fb
2004 * @src_h: height of source rectangle in @fb
2005 * @ctx: lock acquire context
2006 *
2007 * Provides a default plane update handler using the atomic driver interface.
2008 *
2009 * RETURNS:
2010 * Zero on success, error code on failure
2011 */
rockchip_atomic_helper_update_plane(struct drm_plane * plane,struct drm_crtc * crtc,struct drm_framebuffer * fb,int crtc_x,int crtc_y,unsigned int crtc_w,unsigned int crtc_h,uint32_t src_x,uint32_t src_y,uint32_t src_w,uint32_t src_h,struct drm_modeset_acquire_ctx * ctx)2012 static int __maybe_unused rockchip_atomic_helper_update_plane(struct drm_plane *plane, struct drm_crtc *crtc,
2013 struct drm_framebuffer *fb, int crtc_x, int crtc_y,
2014 unsigned int crtc_w, unsigned int crtc_h, uint32_t src_x,
2015 uint32_t src_y, uint32_t src_w, uint32_t src_h,
2016 struct drm_modeset_acquire_ctx *ctx)
2017 {
2018 struct drm_atomic_state *state;
2019 struct drm_plane_state *plane_state;
2020 struct vop_plane_state *vop_plane_state;
2021 int ret = 0;
2022
2023 state = drm_atomic_state_alloc(plane->dev);
2024 if (!state) {
2025 return -ENOMEM;
2026 }
2027
2028 state->acquire_ctx = ctx;
2029 plane_state = drm_atomic_get_plane_state(state, plane);
2030 if (IS_ERR(plane_state)) {
2031 ret = PTR_ERR(plane_state);
2032 goto fail;
2033 }
2034
2035 vop_plane_state = to_vop_plane_state(plane_state);
2036
2037 ret = drm_atomic_set_crtc_for_plane(plane_state, crtc);
2038 if (ret != 0) {
2039 goto fail;
2040 }
2041 drm_atomic_set_fb_for_plane(plane_state, fb);
2042 plane_state->crtc_x = crtc_x;
2043 plane_state->crtc_y = crtc_y;
2044 plane_state->crtc_w = crtc_w;
2045 plane_state->crtc_h = crtc_h;
2046 plane_state->src_x = src_x;
2047 plane_state->src_y = src_y;
2048 plane_state->src_w = src_w;
2049 plane_state->src_h = src_h;
2050
2051 if (plane == crtc->cursor || vop_plane_state->async_commit) {
2052 state->legacy_cursor_update = true;
2053 }
2054
2055 ret = drm_atomic_commit(state);
2056 fail:
2057 drm_atomic_state_put(state);
2058 return ret;
2059 }
2060
2061 /**
2062 * drm_atomic_helper_disable_plane copy from drm_atomic_helper_disable_plane
2063 * be designed to support async commit at ioctl DRM_IOCTL_MODE_SETPLANE.
2064 *
2065 * @plane: plane to disable
2066 * @ctx: lock acquire context
2067 *
2068 * Provides a default plane disable handler using the atomic driver interface.
2069 *
2070 * RETURNS:
2071 * Zero on success, error code on failure
2072 */
rockchip_atomic_helper_disable_plane(struct drm_plane * plane,struct drm_modeset_acquire_ctx * ctx)2073 static int __maybe_unused rockchip_atomic_helper_disable_plane(struct drm_plane *plane,
2074 struct drm_modeset_acquire_ctx *ctx)
2075 {
2076 struct drm_atomic_state *state;
2077 struct drm_plane_state *plane_state;
2078 struct vop_plane_state *vop_plane_state;
2079 int ret = 0;
2080
2081 state = drm_atomic_state_alloc(plane->dev);
2082 if (!state) {
2083 return -ENOMEM;
2084 }
2085
2086 state->acquire_ctx = ctx;
2087 plane_state = drm_atomic_get_plane_state(state, plane);
2088 if (IS_ERR(plane_state)) {
2089 ret = PTR_ERR(plane_state);
2090 goto fail;
2091 }
2092 vop_plane_state = to_vop_plane_state(plane_state);
2093
2094 if ((plane_state->crtc && plane_state->crtc->cursor == plane) || vop_plane_state->async_commit) {
2095 plane_state->state->legacy_cursor_update = true;
2096 }
2097
2098 ret = __drm_atomic_helper_disable_plane(plane, plane_state);
2099 if (ret != 0) {
2100 goto fail;
2101 }
2102
2103 ret = drm_atomic_commit(state);
2104 fail:
2105 drm_atomic_state_put(state);
2106 return ret;
2107 }
2108
vop_plane_destroy(struct drm_plane * plane)2109 static void vop_plane_destroy(struct drm_plane *plane)
2110 {
2111 drm_plane_cleanup(plane);
2112 }
2113
vop_atomic_plane_reset(struct drm_plane * plane)2114 static void vop_atomic_plane_reset(struct drm_plane *plane)
2115 {
2116 struct vop_plane_state *vop_plane_state = to_vop_plane_state(plane->state);
2117 struct vop_win *win = to_vop_win(plane);
2118
2119 if (plane->state && plane->state->fb) {
2120 __drm_atomic_helper_plane_destroy_state(plane->state);
2121 }
2122 kfree(vop_plane_state);
2123 vop_plane_state = kzalloc(sizeof(*vop_plane_state), GFP_KERNEL);
2124 if (!vop_plane_state) {
2125 return;
2126 }
2127
2128 __drm_atomic_helper_plane_reset(plane, &vop_plane_state->base);
2129 win->state.zpos = win->zpos;
2130 vop_plane_state->global_alpha = 0xff;
2131 }
2132
vop_atomic_plane_duplicate_state(struct drm_plane * plane)2133 static struct drm_plane_state *vop_atomic_plane_duplicate_state(struct drm_plane *plane)
2134 {
2135 struct vop_plane_state *old_vop_plane_state;
2136 struct vop_plane_state *vop_plane_state;
2137
2138 if (WARN_ON(!plane->state)) {
2139 return NULL;
2140 }
2141
2142 old_vop_plane_state = to_vop_plane_state(plane->state);
2143 vop_plane_state = kmemdup(old_vop_plane_state, sizeof(*vop_plane_state), GFP_KERNEL);
2144 if (!vop_plane_state) {
2145 return NULL;
2146 }
2147
2148 __drm_atomic_helper_plane_duplicate_state(plane, &vop_plane_state->base);
2149
2150 return &vop_plane_state->base;
2151 }
2152
vop_atomic_plane_destroy_state(struct drm_plane * plane,struct drm_plane_state * state)2153 static void vop_atomic_plane_destroy_state(struct drm_plane *plane, struct drm_plane_state *state)
2154 {
2155 struct vop_plane_state *vop_state = to_vop_plane_state(state);
2156
2157 __drm_atomic_helper_plane_destroy_state(state);
2158
2159 kfree(vop_state);
2160 }
2161
vop_atomic_plane_set_property(struct drm_plane * plane,struct drm_plane_state * state,struct drm_property * property,uint64_t val)2162 static int vop_atomic_plane_set_property(struct drm_plane *plane, struct drm_plane_state *state,
2163 struct drm_property *property, uint64_t val)
2164 {
2165 struct rockchip_drm_private *private = plane->dev->dev_private;
2166 struct vop_win *win = to_vop_win(plane);
2167 struct vop_plane_state *plane_state = to_vop_plane_state(state);
2168
2169 if (property == private->eotf_prop) {
2170 plane_state->eotf = val;
2171 return 0;
2172 }
2173
2174 if (property == private->color_space_prop) {
2175 plane_state->color_space = val;
2176 return 0;
2177 }
2178
2179 if (property == private->async_commit_prop) {
2180 plane_state->async_commit = val;
2181 return 0;
2182 }
2183
2184 if (property == win->color_key_prop) {
2185 plane_state->color_key = val;
2186 return 0;
2187 }
2188
2189 DRM_ERROR("failed to set vop plane property id:%d, name:%s\n", property->base.id, property->name);
2190
2191 return -EINVAL;
2192 }
2193
vop_atomic_plane_get_property(struct drm_plane * plane,const struct drm_plane_state * state,struct drm_property * property,uint64_t * val)2194 static int vop_atomic_plane_get_property(struct drm_plane *plane, const struct drm_plane_state *state,
2195 struct drm_property *property, uint64_t *val)
2196 {
2197 struct vop_plane_state *plane_state = to_vop_plane_state(state);
2198 struct vop_win *win = to_vop_win(plane);
2199 struct rockchip_drm_private *private = plane->dev->dev_private;
2200
2201 if (property == private->eotf_prop) {
2202 *val = plane_state->eotf;
2203 return 0;
2204 }
2205
2206 if (property == private->color_space_prop) {
2207 *val = plane_state->color_space;
2208 return 0;
2209 }
2210
2211 if (property == private->async_commit_prop) {
2212 *val = plane_state->async_commit;
2213 return 0;
2214 }
2215
2216 if (property == private->share_id_prop) {
2217 int i;
2218 struct drm_mode_object *obj = &plane->base;
2219
2220 for (i = 0; i < obj->properties->count; i++) {
2221 if (obj->properties->properties[i] == property) {
2222 *val = obj->properties->values[i];
2223 return 0;
2224 }
2225 }
2226 }
2227
2228 if (property == win->color_key_prop) {
2229 *val = plane_state->color_key;
2230 return 0;
2231 }
2232
2233 DRM_ERROR("failed to get vop plane property id:%d, name:%s\n", property->base.id, property->name);
2234
2235 return -EINVAL;
2236 }
2237
2238 static const struct drm_plane_funcs vop_plane_funcs = {
2239 .update_plane = rockchip_atomic_helper_update_plane,
2240 .disable_plane = rockchip_atomic_helper_disable_plane,
2241 .destroy = vop_plane_destroy,
2242 .reset = vop_atomic_plane_reset,
2243 .atomic_duplicate_state = vop_atomic_plane_duplicate_state,
2244 .atomic_destroy_state = vop_atomic_plane_destroy_state,
2245 .atomic_set_property = vop_atomic_plane_set_property,
2246 .atomic_get_property = vop_atomic_plane_get_property,
2247 };
2248
vop_crtc_enable_vblank(struct drm_crtc * crtc)2249 static int vop_crtc_enable_vblank(struct drm_crtc *crtc)
2250 {
2251 struct vop *vop = to_vop(crtc);
2252 unsigned long flags;
2253
2254 if (WARN_ON(!vop->is_enabled)) {
2255 return -EPERM;
2256 }
2257
2258 spin_lock_irqsave(&vop->irq_lock, flags);
2259
2260 if (VOP_MAJOR(vop->version) == 0x3 && VOP_MINOR(vop->version) >= 0x7) {
2261 VOP_INTR_SET_TYPE(vop, clear, FS_FIELD_INTR, 1);
2262 VOP_INTR_SET_TYPE(vop, enable, FS_FIELD_INTR, 1);
2263 } else {
2264 VOP_INTR_SET_TYPE(vop, clear, FS_INTR, 1);
2265 VOP_INTR_SET_TYPE(vop, enable, FS_INTR, 1);
2266 }
2267
2268 spin_unlock_irqrestore(&vop->irq_lock, flags);
2269
2270 return 0;
2271 }
2272
vop_crtc_disable_vblank(struct drm_crtc * crtc)2273 static void vop_crtc_disable_vblank(struct drm_crtc *crtc)
2274 {
2275 struct vop *vop = to_vop(crtc);
2276 unsigned long flags;
2277
2278 if (WARN_ON(!vop->is_enabled)) {
2279 return;
2280 }
2281
2282 spin_lock_irqsave(&vop->irq_lock, flags);
2283
2284 if (VOP_MAJOR(vop->version) == 0x3 && VOP_MINOR(vop->version) >= 0x7) {
2285 VOP_INTR_SET_TYPE(vop, enable, FS_FIELD_INTR, 0);
2286 } else {
2287 VOP_INTR_SET_TYPE(vop, enable, FS_INTR, 0);
2288 }
2289
2290 spin_unlock_irqrestore(&vop->irq_lock, flags);
2291 }
2292
vop_crtc_cancel_pending_vblank(struct drm_crtc * crtc,struct drm_file * file_priv)2293 static void vop_crtc_cancel_pending_vblank(struct drm_crtc *crtc, struct drm_file *file_priv)
2294 {
2295 struct drm_device *drm = crtc->dev;
2296 struct vop *vop = to_vop(crtc);
2297 struct drm_pending_vblank_event *e;
2298 unsigned long flags;
2299
2300 spin_lock_irqsave(&drm->event_lock, flags);
2301 e = vop->event;
2302 if (e && e->base.file_priv == file_priv) {
2303 vop->event = NULL;
2304 file_priv->event_space += sizeof(e->event);
2305 }
2306 spin_unlock_irqrestore(&drm->event_lock, flags);
2307 }
2308
vop_crtc_loader_protect(struct drm_crtc * crtc,bool on)2309 static int vop_crtc_loader_protect(struct drm_crtc *crtc, bool on)
2310 {
2311 struct rockchip_drm_private *private = crtc->dev->dev_private;
2312 struct vop *vop = to_vop(crtc);
2313 int sys_status = drm_crtc_index(crtc) ? SYS_STATUS_LCDC1 : SYS_STATUS_LCDC0;
2314
2315 if (on == vop->loader_protect) {
2316 return 0;
2317 }
2318
2319 if (on) {
2320 if (vop->dclk_source) {
2321 struct clk *parent;
2322
2323 parent = clk_get_parent(vop->dclk_source);
2324 if (parent) {
2325 if (clk_is_match(private->default_pll.pll, parent)) {
2326 vop->pll = &private->default_pll;
2327 } else if (clk_is_match(private->hdmi_pll.pll, parent)) {
2328 vop->pll = &private->hdmi_pll;
2329 }
2330 if (vop->pll) {
2331 vop->pll->use_count++;
2332 }
2333 }
2334 }
2335
2336 rockchip_set_system_status(sys_status);
2337 vop_initial(crtc);
2338 drm_crtc_vblank_on(crtc);
2339 vop->loader_protect = true;
2340 } else {
2341 vop_crtc_atomic_disable(crtc, NULL);
2342
2343 if (vop->dclk_source && vop->pll) {
2344 vop->pll->use_count--;
2345 vop->pll = NULL;
2346 }
2347 vop->loader_protect = false;
2348 }
2349
2350 return 0;
2351 }
2352
2353 #define DEBUG_PRINT(args...) \
2354 do { \
2355 pr_err(args); \
2356 } while (0)
2357
2358 #define DEBUG_PRINT_S(s, args...) \
2359 do { \
2360 seq_printf(s, args); \
2361 } while (0)
2362
vop_plane_info_dump(struct seq_file * s,struct drm_plane * plane)2363 static int vop_plane_info_dump(struct seq_file *s, struct drm_plane *plane)
2364 {
2365 struct vop_win *win = to_vop_win(plane);
2366 struct drm_plane_state *state = plane->state;
2367 struct vop_plane_state *pstate = to_vop_plane_state(state);
2368 struct drm_rect *src, *dest;
2369 struct drm_framebuffer *fb = state->fb;
2370 struct drm_format_name_buf format_name;
2371 int i;
2372 struct drm_gem_object *obj;
2373 struct rockchip_gem_object *rk_obj;
2374 dma_addr_t fb_addr;
2375 u64 afbdc_format = DRM_FORMAT_MOD_ARM_AFBC(AFBC_FORMAT_MOD_BLOCK_SIZE_16x16);
2376
2377 DEBUG_PRINT(" win%d-%d: %s\n", win->win_id, win->area_id, state->crtc ? "ACTIVE" : "DISABLED");
2378 if (!fb) {
2379 return 0;
2380 }
2381
2382 src = &pstate->src;
2383 dest = &pstate->dest;
2384
2385 drm_get_format_name(fb->format->format, &format_name);
2386 DEBUG_PRINT("\tformat: %s%s%s[%d] color_space[%d]\n", format_name.str, fb->modifier == afbdc_format ? "[AFBC]" : "",
2387 pstate->eotf ? " HDR" : " SDR", pstate->eotf, pstate->color_space);
2388 DEBUG_PRINT("\tcsc: y2r[%d] r2r[%d] r2y[%d] csc mode[%d]\n", pstate->y2r_en, pstate->r2r_en, pstate->r2y_en,
2389 pstate->csc_mode);
2390 DEBUG_PRINT("\tzpos: %d\n", pstate->zpos);
2391 DEBUG_PRINT("\tsrc: pos[%dx%d] rect[%dx%d]\n", src->x1 >> 0x10, src->y1 >> 0x10, drm_rect_width(src) >> 0x10,
2392 drm_rect_height(src) >> 0x10);
2393 DEBUG_PRINT("\tdst: pos[%dx%d] rect[%dx%d]\n", dest->x1, dest->y1, drm_rect_width(dest), drm_rect_height(dest));
2394
2395 for (i = 0; i < fb->format->num_planes; i++) {
2396 obj = fb->obj[0];
2397 rk_obj = to_rockchip_obj(obj);
2398 fb_addr = rk_obj->dma_addr + fb->offsets[0];
2399
2400 DEBUG_PRINT("\tbuf[%d]: addr: %pad pitch: %d offset: %d\n", i, &fb_addr, fb->pitches[i], fb->offsets[i]);
2401 }
2402
2403 return 0;
2404 }
2405
vop_dump_connector_on_crtc(struct drm_crtc * crtc,struct seq_file * s)2406 static void vop_dump_connector_on_crtc(struct drm_crtc *crtc, struct seq_file *s)
2407 {
2408 struct drm_connector_list_iter conn_iter;
2409 struct drm_connector *connector;
2410
2411 drm_connector_list_iter_begin(crtc->dev, &conn_iter);
2412 drm_for_each_connector_iter(connector, &conn_iter)
2413 {
2414 if (crtc->state->connector_mask & drm_connector_mask(connector)) {
2415 DEBUG_PRINT_S(s, " Connector: %s\n", connector->name);
2416 }
2417 }
2418 drm_connector_list_iter_end(&conn_iter);
2419 }
2420
vop_crtc_debugfs_dump(struct drm_crtc * crtc,struct seq_file * s)2421 static int vop_crtc_debugfs_dump(struct drm_crtc *crtc, struct seq_file *s)
2422 {
2423 struct vop *vop = to_vop(crtc);
2424 struct drm_crtc_state *crtc_state = crtc->state;
2425 struct drm_display_mode *mode = &crtc->state->adjusted_mode;
2426 struct rockchip_crtc_state *state = to_rockchip_crtc_state(crtc->state);
2427 bool interlaced = !!(mode->flags & DRM_MODE_FLAG_INTERLACE);
2428 struct drm_plane *plane;
2429 int i;
2430
2431 DEBUG_PRINT_S(s, "VOP [%s]: %s\n", dev_name(vop->dev), crtc_state->active ? "ACTIVE" : "DISABLED");
2432
2433 if (!crtc_state->active) {
2434 return 0;
2435 }
2436
2437 vop_dump_connector_on_crtc(crtc, s);
2438 DEBUG_PRINT_S(s, "\tbus_format[%x]: %s\n", state->bus_format, drm_get_bus_format_name(state->bus_format));
2439 DEBUG_PRINT_S(s, "\toverlay_mode[%d] output_mode[%x]", state->yuv_overlay, state->output_mode);
2440 DEBUG_PRINT_S(s, " color_space[%d]\n", state->color_space);
2441 DEBUG_PRINT_S(s, " Display mode: %dx%d%s%d\n", mode->hdisplay, mode->vdisplay, interlaced ? "i" : "p",
2442 drm_mode_vrefresh(mode));
2443 DEBUG_PRINT_S(s, "\tclk[%d] real_clk[%d] type[%x] flag[%x]\n", mode->clock, mode->crtc_clock, mode->type, \
2444 mode->flags);
2445 DEBUG_PRINT_S(s, "\tH: %d %d %d %d\n", mode->hdisplay, mode->hsync_start, mode->hsync_end, mode->htotal);
2446 DEBUG_PRINT_S(s, "\tV: %d %d %d %d\n", mode->vdisplay, mode->vsync_start, mode->vsync_end, mode->vtotal);
2447
2448 for (i = 0; i < vop->num_wins; i++) {
2449 plane = &vop->win[i].base;
2450 vop_plane_info_dump(s, plane);
2451 }
2452 DEBUG_PRINT_S(s, " post: sdr2hdr[%d] hdr2sdr[%d]\n", state->hdr.sdr2hdr_state.bt1886eotf_post_conv_en,
2453 state->hdr.hdr2sdr_en);
2454 DEBUG_PRINT_S(s, " pre : sdr2hdr[%d]\n", state->hdr.sdr2hdr_state.bt1886eotf_pre_conv_en);
2455 DEBUG_PRINT_S(s, " post CSC: r2y[%d] y2r[%d] CSC mode[%d]\n", state->post_r2y_en, state->post_y2r_en,
2456 state->post_csc_mode);
2457
2458 return 0;
2459 }
2460
vop_crtc_regs_dump(struct drm_crtc * crtc,struct seq_file * s)2461 static void vop_crtc_regs_dump(struct drm_crtc *crtc, struct seq_file *s)
2462 {
2463 struct vop *vop = to_vop(crtc);
2464 struct drm_crtc_state *crtc_state = crtc->state;
2465 int dump_len = vop->len > 0x400 ? 0x400 : vop->len;
2466 int i;
2467
2468 if (!crtc_state->active) {
2469 return;
2470 }
2471
2472 for (i = 0; i < dump_len; i += 0x10) {
2473 DEBUG_PRINT_S(s, "0x%08x: %08x %08x %08x %08x\n", i, vop_readl(vop, i), vop_readl(vop, i + 4),
2474 vop_readl(vop, i + 0x8), vop_readl(vop, i + 0xc));
2475 }
2476 }
2477
vop_gamma_show(struct seq_file * s,void * data)2478 static int vop_gamma_show(struct seq_file *s, void *data)
2479 {
2480 struct drm_info_node *node = s->private;
2481 struct vop *vop = node->info_ent->data;
2482 int i;
2483
2484 if (!vop->lut || !vop->lut_active || !vop->lut_regs) {
2485 return 0;
2486 }
2487
2488 for (i = 0; i < vop->lut_len; i++) {
2489 if (i % 0x8 == 0) {
2490 DEBUG_PRINT_S(s, "\n");
2491 }
2492 DEBUG_PRINT_S(s, "0x%08x ", vop->lut[i]);
2493 }
2494 DEBUG_PRINT_S(s, "\n");
2495
2496 return 0;
2497 }
2498
2499 #undef DEBUG_PRINT
2500 #undef DEBUG_PRINT_S
2501
2502 static struct drm_info_list vop_debugfs_files[] = {
2503 {"gamma_lut", vop_gamma_show, 0, NULL},
2504 };
2505
vop_crtc_debugfs_init(struct drm_minor * minor,struct drm_crtc * crtc)2506 static int vop_crtc_debugfs_init(struct drm_minor *minor, struct drm_crtc *crtc)
2507 {
2508 struct vop *vop = to_vop(crtc);
2509 int ret, i;
2510
2511 vop->debugfs = debugfs_create_dir(dev_name(vop->dev), minor->debugfs_root);
2512
2513 if (!vop->debugfs) {
2514 return -ENOMEM;
2515 }
2516
2517 vop->debugfs_files = kmemdup(vop_debugfs_files, sizeof(vop_debugfs_files), GFP_KERNEL);
2518 if (!vop->debugfs_files) {
2519 ret = -ENOMEM;
2520 goto remove;
2521 }
2522 #if defined(CONFIG_ROCKCHIP_DRM_DEBUG)
2523 rockchip_drm_add_dump_buffer(crtc, vop->debugfs);
2524 #endif
2525 for (i = 0; i < ARRAY_SIZE(vop_debugfs_files); i++) {
2526 vop->debugfs_files[i].data = vop;
2527 }
2528
2529 drm_debugfs_create_files(vop->debugfs_files, ARRAY_SIZE(vop_debugfs_files), vop->debugfs, minor);
2530
2531 return 0;
2532 remove:
2533 debugfs_remove(vop->debugfs);
2534 vop->debugfs = NULL;
2535 return ret;
2536 }
2537
vop_crtc_mode_valid(struct drm_crtc * crtc,const struct drm_display_mode * mode,int output_type)2538 static enum drm_mode_status vop_crtc_mode_valid(struct drm_crtc *crtc, const struct drm_display_mode *mode,
2539 int output_type)
2540 {
2541 struct vop *vop = to_vop(crtc);
2542 const struct vop_data *vop_data = vop->data;
2543 int request_clock = mode->clock;
2544 int clock;
2545
2546 if (mode->hdisplay > vop_data->max_output.width) {
2547 return MODE_BAD_HVALUE;
2548 }
2549
2550 if ((mode->flags & DRM_MODE_FLAG_INTERLACE) && VOP_MAJOR(vop->version) == 0x3 && VOP_MINOR(vop->version) <= 0x2) {
2551 return MODE_BAD;
2552 }
2553
2554 if (mode->flags & DRM_MODE_FLAG_DBLCLK) {
2555 request_clock *= 0x2;
2556 }
2557 clock = clk_round_rate(vop->dclk, request_clock * 0x3e8) / 0x3e8;
2558
2559 /*
2560 * Hdmi or DisplayPort request a Accurate clock.
2561 */
2562 if (output_type == DRM_MODE_CONNECTOR_HDMIA || output_type == DRM_MODE_CONNECTOR_DisplayPort) {
2563 if (clock != request_clock) {
2564 return MODE_CLOCK_RANGE;
2565 }
2566 }
2567
2568 return MODE_OK;
2569 }
2570
2571 struct vop_bandwidth {
2572 size_t bandwidth;
2573 int y1;
2574 int y2;
2575 };
2576
vop_bandwidth_cmp(const void * a,const void * b)2577 static int vop_bandwidth_cmp(const void *a, const void *b)
2578 {
2579 struct vop_bandwidth *pa = (struct vop_bandwidth *)a;
2580 struct vop_bandwidth *pb = (struct vop_bandwidth *)b;
2581
2582 return pa->y1 - pb->y2;
2583 }
2584
vop_plane_line_bandwidth(struct drm_plane_state * pstate)2585 static size_t vop_plane_line_bandwidth(struct drm_plane_state *pstate)
2586 {
2587 struct vop_plane_state *vop_plane_state = to_vop_plane_state(pstate);
2588 struct vop_win *win = to_vop_win(pstate->plane);
2589 struct drm_crtc *crtc = pstate->crtc;
2590 struct vop *vop = to_vop(crtc);
2591 struct drm_framebuffer *fb = pstate->fb;
2592 struct drm_rect *dest = &vop_plane_state->dest;
2593 struct drm_rect *src = &vop_plane_state->src;
2594 int bpp = fb->format->cpp[0] << 0x3;
2595 int src_width = drm_rect_width(src) >> 0x10;
2596 int src_height = drm_rect_height(src) >> 0x10;
2597 int dest_width = drm_rect_width(dest);
2598 int dest_height = drm_rect_height(dest);
2599 int vskiplines = scl_get_vskiplines(src_height, dest_height);
2600 size_t bandwidth;
2601
2602 if (src_width <= 0 || src_height <= 0 || dest_width <= 0 || dest_height <= 0) {
2603 return 0;
2604 }
2605 bandwidth = src_width * bpp / 0x8;
2606
2607 if (dest_width == 0 || dest_height == 0) {
2608 return 0;
2609 }
2610 bandwidth = bandwidth * src_width / dest_width;
2611 bandwidth = bandwidth * src_height / dest_height;
2612 if (vskiplines == 0x2 && VOP_WIN_SCL_EXT_SUPPORT(vop, win, vsd_yrgb_gt2)) {
2613 bandwidth /= 0x2;
2614 } else if (vskiplines == 0x4 && VOP_WIN_SCL_EXT_SUPPORT(vop, win, vsd_yrgb_gt4)) {
2615 bandwidth /= 0x4;
2616 }
2617
2618 return bandwidth;
2619 }
2620
vop_calc_max_bandwidth(struct vop_bandwidth * bw,int start,int count,int y2)2621 static u64 vop_calc_max_bandwidth(struct vop_bandwidth *bw, int start, int count, int y2)
2622 {
2623 u64 max_bandwidth = 0;
2624 int i;
2625
2626 for (i = start; i < count; i++) {
2627 u64 bandwidth = 0;
2628
2629 if (bw[i].y1 > y2) {
2630 continue;
2631 }
2632 bandwidth = bw[i].bandwidth;
2633 bandwidth += vop_calc_max_bandwidth(bw, i + 1, count, min(bw[i].y2, y2));
2634 if (bandwidth > max_bandwidth) {
2635 max_bandwidth = bandwidth;
2636 }
2637 }
2638
2639 return max_bandwidth;
2640 }
2641
vop_crtc_bandwidth(struct drm_crtc * crtc,struct drm_crtc_state * crtc_state,struct dmcfreq_vop_info * vop_bw_info)2642 static size_t vop_crtc_bandwidth(struct drm_crtc *crtc, struct drm_crtc_state *crtc_state,
2643 struct dmcfreq_vop_info *vop_bw_info)
2644 {
2645 struct drm_display_mode *adjusted_mode = &crtc_state->adjusted_mode;
2646 u16 htotal = adjusted_mode->crtc_htotal;
2647 u16 vdisplay = adjusted_mode->crtc_vdisplay;
2648 int clock = adjusted_mode->crtc_clock;
2649 struct vop_plane_state *vop_plane_state;
2650 struct drm_plane_state *pstate;
2651 struct vop_bandwidth *pbandwidth;
2652 struct drm_plane *plane;
2653 u64 line_bw_mbyte = 0;
2654 int cnt = 0, plane_num = 0;
2655 struct drm_atomic_state *state = crtc_state->state;
2656 #if defined(CONFIG_ROCKCHIP_DRM_DEBUG)
2657 struct vop_dump_list *pos, *n;
2658 struct vop *vop = to_vop(crtc);
2659 #endif
2660
2661 if (!htotal || !vdisplay) {
2662 return 0;
2663 }
2664
2665 #if defined(CONFIG_ROCKCHIP_DRM_DEBUG)
2666 if (!vop->rockchip_crtc.vop_dump_list_init_flag) {
2667 INIT_LIST_HEAD(&vop->rockchip_crtc.vop_dump_list_head);
2668 vop->rockchip_crtc.vop_dump_list_init_flag = true;
2669 }
2670 list_for_each_entry_safe(pos, n, &vop->rockchip_crtc.vop_dump_list_head, entry)
2671 {
2672 list_del(&pos->entry);
2673 }
2674 if (vop->rockchip_crtc.vop_dump_status == DUMP_KEEP || vop->rockchip_crtc.vop_dump_times > 0) {
2675 vop->rockchip_crtc.frame_count++;
2676 }
2677 #endif
2678
2679 drm_atomic_crtc_state_for_each_plane(plane, crtc_state) plane_num++;
2680
2681 vop_bw_info->plane_num += plane_num;
2682 pbandwidth = kmalloc_array(plane_num, sizeof(*pbandwidth), GFP_KERNEL);
2683 if (!pbandwidth) {
2684 return -ENOMEM;
2685 }
2686
2687 drm_atomic_crtc_state_for_each_plane(plane, crtc_state)
2688 {
2689 int act_w, act_h, cpp, afbc_fac;
2690
2691 pstate = drm_atomic_get_existing_plane_state(state, plane);
2692 if (pstate->crtc != crtc || !pstate->fb) {
2693 continue;
2694 }
2695
2696 /* This is an empirical value, if it's afbc format, the frame buffer size div 2 */
2697 afbc_fac = rockchip_afbc(plane, pstate->fb->modifier) ? 2 : 1;
2698
2699 vop_plane_state = to_vop_plane_state(pstate);
2700 pbandwidth[cnt].y1 = vop_plane_state->dest.y1;
2701 pbandwidth[cnt].y2 = vop_plane_state->dest.y2;
2702 pbandwidth[cnt++].bandwidth = vop_plane_line_bandwidth(pstate) / afbc_fac;
2703
2704 act_w = drm_rect_width(&pstate->src) >> 0x10;
2705 act_h = drm_rect_height(&pstate->src) >> 0x10;
2706 cpp = pstate->fb->format->cpp[0];
2707
2708 vop_bw_info->frame_bw_mbyte += act_w * act_h / 0x3e8 * cpp * drm_mode_vrefresh(adjusted_mode) / 0x3e8;
2709 }
2710
2711 sort(pbandwidth, cnt, sizeof(pbandwidth[0]), vop_bandwidth_cmp, NULL);
2712
2713 vop_bw_info->line_bw_mbyte = vop_calc_max_bandwidth(pbandwidth, 0, cnt, vdisplay);
2714 kfree(pbandwidth);
2715 /*
2716 * line_bandwidth(MB/s)
2717 * = line_bandwidth / line_time
2718 * = line_bandwidth(Byte) * clock(KHZ) / 1000 / htotal
2719 */
2720 line_bw_mbyte *= clock;
2721 do_div(line_bw_mbyte, htotal * 0x3e8);
2722 vop_bw_info->line_bw_mbyte = line_bw_mbyte;
2723
2724 return vop_bw_info->line_bw_mbyte;
2725 }
2726
vop_crtc_close(struct drm_crtc * crtc)2727 static void vop_crtc_close(struct drm_crtc *crtc)
2728 {
2729 struct vop *vop = NULL;
2730
2731 if (!crtc) {
2732 return;
2733 }
2734 vop = to_vop(crtc);
2735 mutex_lock(&vop->vop_lock);
2736 if (!vop->is_enabled) {
2737 mutex_unlock(&vop->vop_lock);
2738 return;
2739 }
2740
2741 vop_disable_all_planes(vop);
2742 mutex_unlock(&vop->vop_lock);
2743 }
2744
vop_mode_done(struct vop * vop)2745 static u32 vop_mode_done(struct vop *vop)
2746 {
2747 return VOP_CTRL_GET(vop, out_mode);
2748 }
2749
vop_set_out_mode(struct vop * vop,u32 mode)2750 static void vop_set_out_mode(struct vop *vop, u32 mode)
2751 {
2752 int ret;
2753 u32 val;
2754
2755 VOP_CTRL_SET(vop, out_mode, mode);
2756 vop_cfg_done(vop);
2757 ret = readx_poll_timeout(vop_mode_done, vop, val, val == mode, 0x3e8, 0x1f4 * 0x3e8);
2758 if (ret) {
2759 dev_err(vop->dev, "wait mode 0x%x timeout\n", mode);
2760 }
2761 }
2762
vop_crtc_send_mcu_cmd(struct drm_crtc * crtc,u32 type,u32 value)2763 static void vop_crtc_send_mcu_cmd(struct drm_crtc *crtc, u32 type, u32 value)
2764 {
2765 struct rockchip_crtc_state *state;
2766 struct vop *vop = NULL;
2767
2768 if (!crtc) {
2769 return;
2770 }
2771
2772 vop = to_vop(crtc);
2773 state = to_rockchip_crtc_state(crtc->state);
2774
2775 /*
2776 * set output mode to P888 when start send cmd.
2777 */
2778 if ((type == MCU_SETBYPASS) && value) {
2779 vop_set_out_mode(vop, ROCKCHIP_OUT_MODE_P888);
2780 }
2781 mutex_lock(&vop->vop_lock);
2782 if (vop && vop->is_enabled) {
2783 switch (type) {
2784 case MCU_WRCMD:
2785 VOP_CTRL_SET(vop, mcu_rs, 0);
2786 VOP_CTRL_SET(vop, mcu_rw_bypass_port, value);
2787 VOP_CTRL_SET(vop, mcu_rs, 1);
2788 break;
2789 case MCU_WRDATA:
2790 VOP_CTRL_SET(vop, mcu_rs, 1);
2791 VOP_CTRL_SET(vop, mcu_rw_bypass_port, value);
2792 break;
2793 case MCU_SETBYPASS:
2794 VOP_CTRL_SET(vop, mcu_bypass, value ? 1 : 0);
2795 break;
2796 default:
2797 break;
2798 }
2799 }
2800 mutex_unlock(&vop->vop_lock);
2801
2802 /*
2803 * restore output mode at the end
2804 */
2805 if ((type == MCU_SETBYPASS) && !value) {
2806 vop_set_out_mode(vop, state->output_mode);
2807 }
2808 }
2809
2810 static const struct rockchip_crtc_funcs private_crtc_funcs = {
2811 .loader_protect = vop_crtc_loader_protect,
2812 .cancel_pending_vblank = vop_crtc_cancel_pending_vblank,
2813 .debugfs_init = vop_crtc_debugfs_init,
2814 .debugfs_dump = vop_crtc_debugfs_dump,
2815 .regs_dump = vop_crtc_regs_dump,
2816 .mode_valid = vop_crtc_mode_valid,
2817 .bandwidth = vop_crtc_bandwidth,
2818 .crtc_close = vop_crtc_close,
2819 .crtc_send_mcu_cmd = vop_crtc_send_mcu_cmd,
2820 };
2821
vop_crtc_mode_fixup(struct drm_crtc * crtc,const struct drm_display_mode * mode,struct drm_display_mode * adj_mode)2822 static bool vop_crtc_mode_fixup(struct drm_crtc *crtc, const struct drm_display_mode *mode,
2823 struct drm_display_mode *adj_mode)
2824 {
2825 struct vop *vop = to_vop(crtc);
2826 const struct vop_data *vop_data = vop->data;
2827
2828 if (mode->hdisplay > vop_data->max_output.width) {
2829 return false;
2830 }
2831
2832 drm_mode_set_crtcinfo(adj_mode, CRTC_INTERLACE_HALVE_V | CRTC_STEREO_DOUBLE);
2833
2834 if (mode->flags & DRM_MODE_FLAG_DBLCLK) {
2835 adj_mode->crtc_clock *= 0x2;
2836 }
2837
2838 adj_mode->crtc_clock = DIV_ROUND_UP(clk_round_rate(vop->dclk, adj_mode->crtc_clock * 0x3e8), 0x3e8);
2839
2840 return true;
2841 }
2842
vop_dither_setup(struct drm_crtc * crtc)2843 static void vop_dither_setup(struct drm_crtc *crtc)
2844 {
2845 struct rockchip_crtc_state *s = to_rockchip_crtc_state(crtc->state);
2846 struct vop *vop = to_vop(crtc);
2847
2848 /*
2849 * VOP MCU interface can't work right when dither enabled.
2850 * (1) the MCU CMD will be treated as data then changed by dither algorithm
2851 * (2) the dither algorithm works wrong in mcu mode
2852 */
2853 if (vop->mcu_timing.mcu_pix_total) {
2854 return;
2855 }
2856
2857 switch (s->bus_format) {
2858 case MEDIA_BUS_FMT_RGB565_1X16:
2859 VOP_CTRL_SET(vop, dither_down_en, 1);
2860 VOP_CTRL_SET(vop, dither_down_mode, RGB888_TO_RGB565);
2861 break;
2862 case MEDIA_BUS_FMT_RGB666_1X18:
2863 case MEDIA_BUS_FMT_RGB666_1X24_CPADHI:
2864 case MEDIA_BUS_FMT_RGB666_1X7X3_SPWG:
2865 VOP_CTRL_SET(vop, dither_down_en, 1);
2866 VOP_CTRL_SET(vop, dither_down_mode, RGB888_TO_RGB666);
2867 break;
2868 case MEDIA_BUS_FMT_YUV8_1X24:
2869 case MEDIA_BUS_FMT_UYYVYY8_0_5X24:
2870 VOP_CTRL_SET(vop, dither_down_en, 0);
2871 VOP_CTRL_SET(vop, pre_dither_down_en, 1);
2872 break;
2873 case MEDIA_BUS_FMT_YUV10_1X30:
2874 case MEDIA_BUS_FMT_UYYVYY10_0_5X30:
2875 VOP_CTRL_SET(vop, dither_down_en, 0);
2876 VOP_CTRL_SET(vop, pre_dither_down_en, 0);
2877 break;
2878 case MEDIA_BUS_FMT_RGB888_3X8:
2879 case MEDIA_BUS_FMT_RGB888_DUMMY_4X8:
2880 case MEDIA_BUS_FMT_RGB888_1X24:
2881 case MEDIA_BUS_FMT_RGB888_1X7X4_SPWG:
2882 case MEDIA_BUS_FMT_RGB888_1X7X4_JEIDA:
2883 default:
2884 VOP_CTRL_SET(vop, dither_down_en, 0);
2885 VOP_CTRL_SET(vop, pre_dither_down_en, 0);
2886 break;
2887 }
2888
2889 VOP_CTRL_SET(vop, pre_dither_down_en, s->output_mode == ROCKCHIP_OUT_MODE_AAAA ? 0 : 1);
2890 VOP_CTRL_SET(vop, dither_down_sel, DITHER_DOWN_ALLEGRO);
2891 }
2892
vop_update_csc(struct drm_crtc * crtc)2893 static void vop_update_csc(struct drm_crtc *crtc)
2894 {
2895 struct rockchip_crtc_state *s = to_rockchip_crtc_state(crtc->state);
2896 struct vop *vop = to_vop(crtc);
2897 u32 val;
2898
2899 if (s->output_mode == ROCKCHIP_OUT_MODE_AAAA && !(vop->data->feature & VOP_FEATURE_OUTPUT_10BIT)) {
2900 s->output_mode = ROCKCHIP_OUT_MODE_P888;
2901 }
2902
2903 if (is_uv_swap(s->bus_format, s->output_mode)) {
2904 VOP_CTRL_SET(vop, dsp_data_swap, DSP_RB_SWAP);
2905 } else {
2906 VOP_CTRL_SET(vop, dsp_data_swap, 0);
2907 }
2908
2909 VOP_CTRL_SET(vop, out_mode, s->output_mode);
2910
2911 vop_dither_setup(crtc);
2912 VOP_CTRL_SET(vop, dclk_ddr, s->output_mode == ROCKCHIP_OUT_MODE_YUV420 ? 1 : 0);
2913 VOP_CTRL_SET(vop, hdmi_dclk_out_en, s->output_mode == ROCKCHIP_OUT_MODE_YUV420 ? 1 : 0);
2914
2915 VOP_CTRL_SET(vop, overlay_mode, s->yuv_overlay);
2916 VOP_CTRL_SET(vop, dsp_out_yuv, is_yuv_output(s->bus_format));
2917
2918 /*
2919 * Background color is 10bit depth if vop version >= 3.5
2920 */
2921 if (!is_yuv_output(s->bus_format)) {
2922 val = 0;
2923 } else if (VOP_MAJOR(vop->version) == 0x3 && VOP_MINOR(vop->version) == 0x8 && s->hdr.pre_overlay) {
2924 val = 0;
2925 } else if (VOP_MAJOR(vop->version) == 0x3 && VOP_MINOR(vop->version) >= 0x5) {
2926 val = 0x20010200;
2927 } else {
2928 val = 0x801080;
2929 }
2930 VOP_CTRL_SET(vop, dsp_background, val);
2931 }
2932
2933 /*
2934 * if adjusted mode update, return true, else return false
2935 */
vop_crtc_mode_update(struct drm_crtc * crtc)2936 static bool vop_crtc_mode_update(struct drm_crtc *crtc)
2937 {
2938 struct vop *vop = to_vop(crtc);
2939 struct drm_display_mode *adjusted_mode = &crtc->state->adjusted_mode;
2940 u16 hsync_len = adjusted_mode->crtc_hsync_end - adjusted_mode->crtc_hsync_start;
2941 u16 hdisplay = adjusted_mode->crtc_hdisplay;
2942 u16 htotal = adjusted_mode->crtc_htotal;
2943 u16 hact_st = adjusted_mode->crtc_htotal - adjusted_mode->crtc_hsync_start;
2944 u16 hact_end = hact_st + hdisplay;
2945 u16 vdisplay = adjusted_mode->crtc_vdisplay;
2946 u16 vtotal = adjusted_mode->crtc_vtotal;
2947 u16 vsync_len = adjusted_mode->crtc_vsync_end - adjusted_mode->crtc_vsync_start;
2948 u16 vact_st = adjusted_mode->crtc_vtotal - adjusted_mode->crtc_vsync_start;
2949 u16 vact_end = vact_st + vdisplay;
2950 u32 htotal_sync = (htotal << 0x10) | hsync_len;
2951 u32 hactive_st_end = (hact_st << 0x10) | hact_end;
2952 u32 vtotal_sync = (vtotal << 0x10) | vsync_len;
2953 u32 vactive_st_end = (vact_st << 0x10) | vact_end;
2954 u32 crtc_clock = adjusted_mode->crtc_clock * 0x64;
2955
2956 if (htotal_sync != VOP_CTRL_GET(vop, htotal_pw) || hactive_st_end != VOP_CTRL_GET(vop, hact_st_end) ||
2957 vtotal_sync != VOP_CTRL_GET(vop, vtotal_pw) || vactive_st_end != VOP_CTRL_GET(vop, vact_st_end) ||
2958 crtc_clock != clk_get_rate(vop->dclk)) {
2959 return true;
2960 }
2961
2962 return false;
2963 }
2964
vop_mcu_mode(struct drm_crtc * crtc)2965 static void vop_mcu_mode(struct drm_crtc *crtc)
2966 {
2967 struct vop *vop = to_vop(crtc);
2968
2969 VOP_CTRL_SET(vop, mcu_clk_sel, 1);
2970 VOP_CTRL_SET(vop, mcu_type, 1);
2971
2972 VOP_CTRL_SET(vop, mcu_hold_mode, 1);
2973 VOP_CTRL_SET(vop, mcu_pix_total, vop->mcu_timing.mcu_pix_total);
2974 VOP_CTRL_SET(vop, mcu_cs_pst, vop->mcu_timing.mcu_cs_pst);
2975 VOP_CTRL_SET(vop, mcu_cs_pend, vop->mcu_timing.mcu_cs_pend);
2976 VOP_CTRL_SET(vop, mcu_rw_pst, vop->mcu_timing.mcu_rw_pst);
2977 VOP_CTRL_SET(vop, mcu_rw_pend, vop->mcu_timing.mcu_rw_pend);
2978 }
2979
vop_crtc_atomic_enable(struct drm_crtc * crtc,struct drm_crtc_state * old_state)2980 static void vop_crtc_atomic_enable(struct drm_crtc *crtc, struct drm_crtc_state *old_state)
2981 {
2982 struct vop *vop = to_vop(crtc);
2983 struct rockchip_crtc_state *s = to_rockchip_crtc_state(crtc->state);
2984 struct drm_display_mode *adjusted_mode = &crtc->state->adjusted_mode;
2985 u16 hsync_len = adjusted_mode->crtc_hsync_end - adjusted_mode->crtc_hsync_start;
2986 u16 hdisplay = adjusted_mode->crtc_hdisplay;
2987 u16 htotal = adjusted_mode->crtc_htotal;
2988 u16 hact_st = adjusted_mode->crtc_htotal - adjusted_mode->crtc_hsync_start;
2989 u16 hact_end = hact_st + hdisplay;
2990 u16 vdisplay = adjusted_mode->crtc_vdisplay;
2991 u16 vtotal = adjusted_mode->crtc_vtotal;
2992 u16 vsync_len = adjusted_mode->crtc_vsync_end - adjusted_mode->crtc_vsync_start;
2993 u16 vact_st = adjusted_mode->crtc_vtotal - adjusted_mode->crtc_vsync_start;
2994 u16 vact_end = vact_st + vdisplay;
2995 int sys_status = drm_crtc_index(crtc) ? SYS_STATUS_LCDC1 : SYS_STATUS_LCDC0;
2996 uint32_t val;
2997 int act_end;
2998 bool interlaced = !!(adjusted_mode->flags & DRM_MODE_FLAG_INTERLACE);
2999 int for_ddr_freq = 0;
3000 bool dclk_inv, yc_swap = false;
3001
3002 rockchip_set_system_status(sys_status);
3003 vop_lock(vop);
3004 DRM_DEV_INFO(vop->dev, "Update mode to %dx%d%s%d, type: %d\n", hdisplay, vdisplay, interlaced ? "i" : "p",
3005 drm_mode_vrefresh(adjusted_mode), s->output_type);
3006 vop_initial(crtc);
3007 vop_disable_allwin(vop);
3008 VOP_CTRL_SET(vop, standby, 0);
3009 s->mode_update = vop_crtc_mode_update(crtc);
3010 if (s->mode_update) {
3011 vop_disable_all_planes(vop);
3012 }
3013 /*
3014 * restore the lut table.
3015 */
3016 if (vop->lut_active) {
3017 vop_crtc_load_lut(crtc);
3018 }
3019
3020 if (vop->mcu_timing.mcu_pix_total) {
3021 vop_mcu_mode(crtc);
3022 }
3023
3024 dclk_inv = (s->bus_flags & DRM_BUS_FLAG_PIXDATA_DRIVE_NEGEDGE) ? 1 : 0;
3025
3026 VOP_CTRL_SET(vop, dclk_pol, dclk_inv);
3027 val = (adjusted_mode->flags & DRM_MODE_FLAG_NHSYNC) ? 0 : BIT(HSYNC_POSITIVE);
3028 val |= (adjusted_mode->flags & DRM_MODE_FLAG_NVSYNC) ? 0 : BIT(VSYNC_POSITIVE);
3029 VOP_CTRL_SET(vop, pin_pol, val);
3030
3031 if (vop->dclk_source && vop->pll && vop->pll->pll) {
3032 if (clk_set_parent(vop->dclk_source, vop->pll->pll)) {
3033 DRM_DEV_ERROR(vop->dev, "failed to set dclk's parents\n");
3034 }
3035 }
3036
3037 switch (s->output_type) {
3038 case DRM_MODE_CONNECTOR_DPI:
3039 case DRM_MODE_CONNECTOR_LVDS:
3040 VOP_CTRL_SET(vop, rgb_en, 1);
3041 VOP_CTRL_SET(vop, rgb_pin_pol, val);
3042 VOP_CTRL_SET(vop, rgb_dclk_pol, dclk_inv);
3043 VOP_CTRL_SET(vop, lvds_en, 1);
3044 VOP_CTRL_SET(vop, lvds_pin_pol, val);
3045 VOP_CTRL_SET(vop, lvds_dclk_pol, dclk_inv);
3046 VOP_GRF_SET(vop, grf_dclk_inv, dclk_inv);
3047 if (s->output_if & VOP_OUTPUT_IF_BT1120) {
3048 VOP_CTRL_SET(vop, bt1120_en, 1);
3049 yc_swap = is_yc_swap(s->bus_format);
3050 VOP_CTRL_SET(vop, bt1120_yc_swap, yc_swap);
3051 VOP_CTRL_SET(vop, yuv_clip, 1);
3052 }
3053 break;
3054 case DRM_MODE_CONNECTOR_eDP:
3055 VOP_CTRL_SET(vop, edp_en, 1);
3056 VOP_CTRL_SET(vop, edp_pin_pol, val);
3057 VOP_CTRL_SET(vop, edp_dclk_pol, dclk_inv);
3058 break;
3059 case DRM_MODE_CONNECTOR_HDMIA:
3060 VOP_CTRL_SET(vop, hdmi_en, 1);
3061 VOP_CTRL_SET(vop, hdmi_pin_pol, val);
3062 VOP_CTRL_SET(vop, hdmi_dclk_pol, 1);
3063 break;
3064 case DRM_MODE_CONNECTOR_DSI:
3065 VOP_CTRL_SET(vop, mipi_en, 1);
3066 VOP_CTRL_SET(vop, mipi_pin_pol, val);
3067 VOP_CTRL_SET(vop, mipi_dclk_pol, dclk_inv);
3068 VOP_CTRL_SET(vop, mipi_dual_channel_en, !!(s->output_flags & ROCKCHIP_OUTPUT_DUAL_CHANNEL_LEFT_RIGHT_MODE));
3069 VOP_CTRL_SET(vop, data01_swap, !!(s->output_flags & ROCKCHIP_OUTPUT_DATA_SWAP) || vop->dual_channel_swap);
3070 break;
3071 case DRM_MODE_CONNECTOR_DisplayPort:
3072 VOP_CTRL_SET(vop, dp_dclk_pol, 0);
3073 VOP_CTRL_SET(vop, dp_pin_pol, val);
3074 VOP_CTRL_SET(vop, dp_en, 1);
3075 break;
3076 case DRM_MODE_CONNECTOR_TV:
3077 if (vdisplay == CVBS_PAL_VDISPLAY) {
3078 VOP_CTRL_SET(vop, tve_sw_mode, 1);
3079 } else {
3080 VOP_CTRL_SET(vop, tve_sw_mode, 0);
3081 }
3082
3083 VOP_CTRL_SET(vop, tve_dclk_pol, 1);
3084 VOP_CTRL_SET(vop, tve_dclk_en, 1);
3085 /* use the same pol reg with hdmi */
3086 VOP_CTRL_SET(vop, hdmi_pin_pol, val);
3087 VOP_CTRL_SET(vop, sw_genlock, 1);
3088 VOP_CTRL_SET(vop, sw_uv_offset_en, 1);
3089 VOP_CTRL_SET(vop, dither_up_en, 1);
3090 break;
3091 default:
3092 DRM_ERROR("unsupported connector_type[%d]\n", s->output_type);
3093 }
3094 vop_update_csc(crtc);
3095 VOP_CTRL_SET(vop, htotal_pw, (htotal << 0x10) | hsync_len);
3096 val = hact_st << 0x10;
3097 val |= hact_end;
3098 VOP_CTRL_SET(vop, hact_st_end, val);
3099 VOP_CTRL_SET(vop, hpost_st_end, val);
3100
3101 val = vact_st << 0x10;
3102 val |= vact_end;
3103 VOP_CTRL_SET(vop, vact_st_end, val);
3104 VOP_CTRL_SET(vop, vpost_st_end, val);
3105
3106 if (adjusted_mode->flags & DRM_MODE_FLAG_INTERLACE) {
3107 u16 vact_st_f1 = vtotal + vact_st + 1;
3108 u16 vact_end_f1 = vact_st_f1 + vdisplay;
3109
3110 val = (vact_st_f1 << 0x10) | vact_end_f1;
3111 VOP_CTRL_SET(vop, vact_st_end_f1, val);
3112 VOP_CTRL_SET(vop, vpost_st_end_f1, val);
3113
3114 val = (vtotal << 0x10) | (vtotal + vsync_len);
3115 VOP_CTRL_SET(vop, vs_st_end_f1, val);
3116 VOP_CTRL_SET(vop, dsp_interlace, 1);
3117 VOP_CTRL_SET(vop, p2i_en, 1);
3118 vtotal += vtotal + 1;
3119 act_end = vact_end_f1;
3120 } else {
3121 VOP_CTRL_SET(vop, dsp_interlace, 0);
3122 VOP_CTRL_SET(vop, p2i_en, 0);
3123 act_end = vact_end;
3124 }
3125
3126 if (VOP_MAJOR(vop->version) == 0x3 && (VOP_MINOR(vop->version) == 0x2 || VOP_MINOR(vop->version) == 0x8)) {
3127 for_ddr_freq = 0x3e8;
3128 }
3129 VOP_INTR_SET(vop, line_flag_num[0], act_end);
3130 VOP_INTR_SET(vop, line_flag_num[1], act_end - us_to_vertical_line(adjusted_mode, for_ddr_freq));
3131
3132 VOP_CTRL_SET(vop, vtotal_pw, (vtotal << 0x10) | vsync_len);
3133
3134 VOP_CTRL_SET(vop, core_dclk_div, !!(adjusted_mode->flags & DRM_MODE_FLAG_DBLCLK));
3135
3136 VOP_CTRL_SET(vop, win_csc_mode_sel, 1);
3137
3138 clk_set_rate(vop->dclk, adjusted_mode->crtc_clock * 0x3e8);
3139
3140 vop_cfg_done(vop);
3141
3142 drm_crtc_vblank_on(crtc);
3143 vop_unlock(vop);
3144 }
3145
vop_zpos_cmp(const void * a,const void * b)3146 static int vop_zpos_cmp(const void *a, const void *b)
3147 {
3148 struct vop_zpos *pa = (struct vop_zpos *)a;
3149 struct vop_zpos *pb = (struct vop_zpos *)b;
3150
3151 return pa->zpos - pb->zpos;
3152 }
3153
vop_afbdc_atomic_check(struct drm_crtc * crtc,struct drm_crtc_state * crtc_state)3154 static int vop_afbdc_atomic_check(struct drm_crtc *crtc, struct drm_crtc_state *crtc_state)
3155 {
3156 struct vop *vop = to_vop(crtc);
3157 struct rockchip_crtc_state *s = to_rockchip_crtc_state(crtc_state);
3158 struct drm_atomic_state *state = crtc_state->state;
3159 struct drm_plane *plane;
3160 struct drm_plane_state *pstate;
3161 struct vop_plane_state *plane_state;
3162 struct drm_framebuffer *fb;
3163 struct drm_rect *src;
3164 struct vop_win *win;
3165 int afbdc_format;
3166
3167 s->afbdc_en = 0;
3168
3169 drm_atomic_crtc_state_for_each_plane(plane, crtc_state)
3170 {
3171 pstate = drm_atomic_get_existing_plane_state(state, plane);
3172 /*
3173 * plane might not have changed, in which case take
3174 * current state:
3175 */
3176 if (!pstate) {
3177 pstate = plane->state;
3178 }
3179
3180 fb = pstate->fb;
3181
3182 if (pstate->crtc != crtc || !fb) {
3183 continue;
3184 }
3185 if (fb->modifier != DRM_FORMAT_MOD_ARM_AFBC(AFBC_FORMAT_MOD_BLOCK_SIZE_16x16)) {
3186 continue;
3187 }
3188
3189 if (!VOP_CTRL_SUPPORT(vop, afbdc_en)) {
3190 DRM_INFO("not support afbdc\n");
3191 return -EINVAL;
3192 }
3193
3194 plane_state = to_vop_plane_state(pstate);
3195
3196 switch (plane_state->format) {
3197 case VOP_FMT_ARGB8888:
3198 afbdc_format = AFBDC_FMT_U8U8U8U8;
3199 break;
3200 case VOP_FMT_RGB888:
3201 afbdc_format = AFBDC_FMT_U8U8U8;
3202 break;
3203 case VOP_FMT_RGB565:
3204 afbdc_format = AFBDC_FMT_RGB565;
3205 break;
3206 default:
3207 return -EINVAL;
3208 }
3209
3210 if (s->afbdc_en) {
3211 DRM_ERROR("vop only support one afbc layer\n");
3212 return -EINVAL;
3213 }
3214
3215 win = to_vop_win(plane);
3216 src = &plane_state->src;
3217 if (!(win->feature & WIN_FEATURE_AFBDC)) {
3218 DRM_ERROR("win[%d] feature:0x%llx, not support afbdc\n", win->win_id, win->feature);
3219 return -EINVAL;
3220 }
3221 if (!IS_ALIGNED(fb->width, 0x10)) {
3222 DRM_ERROR("win[%d] afbdc must 16 align, width: %d\n", win->win_id, fb->width);
3223 return -EINVAL;
3224 }
3225
3226 if (VOP_CTRL_SUPPORT(vop, afbdc_pic_vir_width)) {
3227 u32 align_x1, align_x2, align_y1, align_y2, align_val;
3228 struct drm_gem_object *obj;
3229 struct rockchip_gem_object *rk_obj;
3230 dma_addr_t fb_addr;
3231
3232 obj = fb->obj[0];
3233 rk_obj = to_rockchip_obj(obj);
3234 fb_addr = rk_obj->dma_addr + fb->offsets[0];
3235
3236 s->afbdc_win_format = afbdc_format;
3237 s->afbdc_win_id = win->win_id;
3238 s->afbdc_win_ptr = fb_addr;
3239 s->afbdc_win_vir_width = fb->width;
3240 s->afbdc_win_xoffset = (src->x1 >> 0x10);
3241 s->afbdc_win_yoffset = (src->y1 >> 0x10);
3242
3243 align_x1 = (src->x1 >> 0x10) - ((src->x1 >> 0x10) % 0x10);
3244 align_y1 = (src->y1 >> 0x10) - ((src->y1 >> 0x10) % 0x10);
3245
3246 align_val = (src->x2 >> 0x10) % 0x10;
3247 if (align_val) {
3248 align_x2 = (src->x2 >> 0x10) + (0x10 - align_val);
3249 } else {
3250 align_x2 = src->x2 >> 0x10;
3251 }
3252
3253 align_val = (src->y2 >> 0x10) % 0x10;
3254 if (align_val) {
3255 align_y2 = (src->y2 >> 0x10) + (0x10 - align_val);
3256 } else {
3257 align_y2 = src->y2 >> 0x10;
3258 }
3259
3260 s->afbdc_win_width = align_x2 - align_x1 - 1;
3261 s->afbdc_win_height = align_y2 - align_y1 - 1;
3262
3263 s->afbdc_en = 1;
3264
3265 break;
3266 }
3267 if (src->x1 || src->y1 || fb->offsets[0]) {
3268 DRM_ERROR("win[%d] afbdc not support offset display\n", win->win_id);
3269 DRM_ERROR("xpos=%d, ypos=%d, offset=%d\n", src->x1, src->y1, fb->offsets[0]);
3270 return -EINVAL;
3271 }
3272 s->afbdc_win_format = afbdc_format;
3273 s->afbdc_win_width = fb->width - 1;
3274 s->afbdc_win_height = (drm_rect_height(src) >> 0x10) - 1;
3275 s->afbdc_win_id = win->win_id;
3276 s->afbdc_win_ptr = plane_state->yrgb_mst;
3277 s->afbdc_en = 1;
3278 }
3279
3280 return 0;
3281 }
3282
vop_dclk_source_generate(struct drm_crtc * crtc,struct drm_crtc_state * crtc_state)3283 static void vop_dclk_source_generate(struct drm_crtc *crtc, struct drm_crtc_state *crtc_state)
3284 {
3285 struct rockchip_drm_private *private = crtc->dev->dev_private;
3286 struct rockchip_crtc_state *s = to_rockchip_crtc_state(crtc_state);
3287 struct rockchip_crtc_state *old_s = to_rockchip_crtc_state(crtc->state);
3288 struct vop *vop = to_vop(crtc);
3289 struct rockchip_dclk_pll *old_pll = vop->pll;
3290
3291 if (!vop->dclk_source) {
3292 return;
3293 }
3294
3295 if (crtc_state->active) {
3296 WARN_ON(vop->pll && !vop->pll->use_count);
3297 if (!vop->pll || vop->pll->use_count > 1 || s->output_type != old_s->output_type) {
3298 if (vop->pll) {
3299 vop->pll->use_count--;
3300 }
3301
3302 if (s->output_type != DRM_MODE_CONNECTOR_HDMIA && !private->default_pll.use_count) {
3303 vop->pll = &private->default_pll;
3304 } else {
3305 vop->pll = &private->hdmi_pll;
3306 }
3307
3308 vop->pll->use_count++;
3309 }
3310 } else if (vop->pll) {
3311 vop->pll->use_count--;
3312 vop->pll = NULL;
3313 }
3314 if (vop->pll != old_pll) {
3315 crtc_state->mode_changed = true;
3316 }
3317 }
3318
vop_crtc_atomic_check(struct drm_crtc * crtc,struct drm_crtc_state * crtc_state)3319 static int vop_crtc_atomic_check(struct drm_crtc *crtc, struct drm_crtc_state *crtc_state)
3320 {
3321 struct drm_atomic_state *state = crtc_state->state;
3322 struct rockchip_crtc_state *s = to_rockchip_crtc_state(crtc_state);
3323 struct vop *vop = to_vop(crtc);
3324 const struct vop_data *vop_data = vop->data;
3325 struct drm_plane *plane;
3326 struct drm_plane_state *pstate;
3327 struct vop_plane_state *plane_state;
3328 struct vop_zpos *pzpos;
3329 int dsp_layer_sel = 0;
3330 int i, j, cnt = 0, ret = 0;
3331
3332 ret = vop_afbdc_atomic_check(crtc, crtc_state);
3333 if (ret) {
3334 return ret;
3335 }
3336
3337 s->yuv_overlay = 0;
3338 if (VOP_CTRL_SUPPORT(vop, overlay_mode)) {
3339 s->yuv_overlay = is_yuv_output(s->bus_format);
3340 }
3341
3342 ret = vop_hdr_atomic_check(crtc, crtc_state);
3343 if (ret) {
3344 return ret;
3345 }
3346 ret = vop_csc_atomic_check(crtc, crtc_state);
3347 if (ret) {
3348 return ret;
3349 }
3350
3351 pzpos = kmalloc_array(vop_data->win_size, sizeof(*pzpos), GFP_KERNEL);
3352 if (!pzpos) {
3353 return -ENOMEM;
3354 }
3355
3356 for (i = 0; i < vop_data->win_size; i++) {
3357 const struct vop_win_data *win_data = &vop_data->win[i];
3358 struct vop_win *win;
3359
3360 if (!win_data->phy) {
3361 continue;
3362 }
3363
3364 for (j = 0; j < vop->num_wins; j++) {
3365 win = &vop->win[j];
3366
3367 if (win->win_id == i && !win->area_id) {
3368 break;
3369 }
3370 }
3371 if (WARN_ON(j >= vop->num_wins)) {
3372 ret = -EINVAL;
3373 goto err_free_pzpos;
3374 }
3375
3376 plane = &win->base;
3377 pstate = state->planes[drm_plane_index(plane)].state;
3378 /*
3379 * plane might not have changed, in which case take
3380 * current state:
3381 */
3382 if (!pstate) {
3383 pstate = plane->state;
3384 }
3385 plane_state = to_vop_plane_state(pstate);
3386
3387 if (!pstate->visible) {
3388 pzpos[cnt].zpos = INT_MAX;
3389 } else {
3390 pzpos[cnt].zpos = plane_state->zpos;
3391 }
3392 pzpos[cnt++].win_id = win->win_id;
3393 }
3394
3395 sort(pzpos, cnt, sizeof(pzpos[0]), vop_zpos_cmp, NULL);
3396
3397 for (i = 0, cnt = 0; i < vop_data->win_size; i++) {
3398 const struct vop_win_data *win_data = &vop_data->win[i];
3399 int shift = i * 0x2;
3400
3401 if (win_data->phy) {
3402 struct vop_zpos *zpos = &pzpos[cnt++];
3403
3404 dsp_layer_sel |= zpos->win_id << shift;
3405 } else {
3406 dsp_layer_sel |= i << shift;
3407 }
3408 }
3409
3410 s->dsp_layer_sel = dsp_layer_sel;
3411
3412 vop_dclk_source_generate(crtc, crtc_state);
3413
3414 err_free_pzpos:
3415 kfree(pzpos);
3416 return ret;
3417 }
3418
vop_post_config(struct drm_crtc * crtc)3419 static void vop_post_config(struct drm_crtc *crtc)
3420 {
3421 struct vop *vop = to_vop(crtc);
3422 struct rockchip_crtc_state *s = to_rockchip_crtc_state(crtc->state);
3423 struct drm_display_mode *mode = &crtc->state->adjusted_mode;
3424 u16 vtotal = mode->crtc_vtotal;
3425 u16 hdisplay = mode->crtc_hdisplay;
3426 u16 hact_st = mode->crtc_htotal - mode->crtc_hsync_start;
3427 u16 vdisplay = mode->crtc_vdisplay;
3428 u16 vact_st = mode->crtc_vtotal - mode->crtc_vsync_start;
3429 u16 hsize = hdisplay * (s->left_margin + s->right_margin) / 0xc8;
3430 u16 vsize = vdisplay * (s->top_margin + s->bottom_margin) / 0xc8;
3431 u16 hact_end, vact_end;
3432 u32 val;
3433
3434 if (mode->flags & DRM_MODE_FLAG_INTERLACE) {
3435 vsize = rounddown(vsize, 0x2);
3436 }
3437
3438 hact_st += hdisplay * (0x64 - s->left_margin) / 0xc8;
3439 hact_end = hact_st + hsize;
3440 val = hact_st << 0x10;
3441 val |= hact_end;
3442 VOP_CTRL_SET(vop, hpost_st_end, val);
3443 vact_st += vdisplay * (0x64 - s->top_margin) / 0xc8;
3444 vact_end = vact_st + vsize;
3445 val = vact_st << 0x10;
3446 val |= vact_end;
3447 VOP_CTRL_SET(vop, vpost_st_end, val);
3448 val = scl_cal_scale2(vdisplay, vsize) << 0x10;
3449 val |= scl_cal_scale2(hdisplay, hsize);
3450 VOP_CTRL_SET(vop, post_scl_factor, val);
3451
3452 #define POST_HORIZONTAL_SCALEDOWN_EN(x) ((x) << 0)
3453 #define POST_VERTICAL_SCALEDOWN_EN(x) ((x) << 1)
3454 VOP_CTRL_SET(vop, post_scl_ctrl,
3455 POST_HORIZONTAL_SCALEDOWN_EN(hdisplay != hsize) | POST_VERTICAL_SCALEDOWN_EN(vdisplay != vsize));
3456 if (mode->flags & DRM_MODE_FLAG_INTERLACE) {
3457 u16 vact_st_f1 = vtotal + vact_st + 1;
3458 u16 vact_end_f1 = vact_st_f1 + vsize;
3459
3460 val = (vact_st_f1 << 0x10) | vact_end_f1;
3461 VOP_CTRL_SET(vop, vpost_st_end_f1, val);
3462 }
3463 }
3464
vop_update_hdr(struct drm_crtc * crtc,struct drm_crtc_state * old_crtc_state)3465 static void vop_update_hdr(struct drm_crtc *crtc, struct drm_crtc_state *old_crtc_state)
3466 {
3467 struct rockchip_crtc_state *s = to_rockchip_crtc_state(crtc->state);
3468 struct vop *vop = to_vop(crtc);
3469 struct rockchip_sdr2hdr_state *sdr2hdr_state = &s->hdr.sdr2hdr_state;
3470
3471 if (!vop->data->hdr_table) {
3472 return;
3473 }
3474
3475 if (s->hdr.hdr2sdr_en) {
3476 vop_load_hdr2sdr_table(vop);
3477 /* This is ic design bug, when in hdr2sdr mode, the overlay mode
3478 * is rgb domain, so the win0 is do yuv2rgb, but in this case,
3479 * we must close win0 y2r.
3480 */
3481 VOP_CTRL_SET(vop, hdr2sdr_en_win0_csc, 0);
3482 }
3483 VOP_CTRL_SET(vop, hdr2sdr_en, s->hdr.hdr2sdr_en);
3484
3485 VOP_CTRL_SET(vop, bt1886eotf_pre_conv_en, sdr2hdr_state->bt1886eotf_pre_conv_en);
3486 VOP_CTRL_SET(vop, bt1886eotf_post_conv_en, sdr2hdr_state->bt1886eotf_post_conv_en);
3487
3488 VOP_CTRL_SET(vop, rgb2rgb_pre_conv_en, sdr2hdr_state->rgb2rgb_pre_conv_en);
3489 VOP_CTRL_SET(vop, rgb2rgb_pre_conv_mode, sdr2hdr_state->rgb2rgb_pre_conv_mode);
3490 VOP_CTRL_SET(vop, st2084oetf_pre_conv_en, sdr2hdr_state->st2084oetf_pre_conv_en);
3491
3492 VOP_CTRL_SET(vop, rgb2rgb_post_conv_en, sdr2hdr_state->rgb2rgb_post_conv_en);
3493 VOP_CTRL_SET(vop, rgb2rgb_post_conv_mode, sdr2hdr_state->rgb2rgb_post_conv_mode);
3494 VOP_CTRL_SET(vop, st2084oetf_post_conv_en, sdr2hdr_state->st2084oetf_post_conv_en);
3495
3496 if (sdr2hdr_state->bt1886eotf_pre_conv_en || sdr2hdr_state->bt1886eotf_post_conv_en) {
3497 vop_load_sdr2hdr_table(vop, sdr2hdr_state->sdr2hdr_func);
3498 }
3499 VOP_CTRL_SET(vop, win_csc_mode_sel, 1);
3500 }
3501
vop_tv_config_update(struct drm_crtc * crtc,struct drm_crtc_state * old_crtc_state)3502 static void vop_tv_config_update(struct drm_crtc *crtc, struct drm_crtc_state *old_crtc_state)
3503 {
3504 struct rockchip_crtc_state *s = to_rockchip_crtc_state(crtc->state);
3505 struct rockchip_crtc_state *old_s = to_rockchip_crtc_state(old_crtc_state);
3506 int brightness, contrast, saturation, hue, sin_hue, cos_hue;
3507 struct vop *vop = to_vop(crtc);
3508 const struct vop_data *vop_data = vop->data;
3509
3510 if (!s->tv_state) {
3511 return;
3512 }
3513
3514 /*
3515 * The BCSH only need to config once except one of the following
3516 * condition changed:
3517 * 1. tv_state: include brightness,contrast,saturation and hue;
3518 * 2. yuv_overlay: it is related to BCSH r2y module;
3519 * 3. mode_update: it is indicate mode change and resume from suspend;
3520 * 4. bcsh_en: control the BCSH module enable or disable state;
3521 * 5. bus_format: it is related to BCSH y2r module;
3522 */
3523 if (!memcmp(s->tv_state, &vop->active_tv_state, sizeof(*s->tv_state)) && s->yuv_overlay == old_s->yuv_overlay &&
3524 s->mode_update && s->bcsh_en == old_s->bcsh_en && s->bus_format == old_s->bus_format) {
3525 return;
3526 }
3527
3528 memcpy(&vop->active_tv_state, s->tv_state, sizeof(*s->tv_state));
3529 /* post BCSH CSC */
3530 s->post_r2y_en = 0;
3531 s->post_y2r_en = 0;
3532 s->bcsh_en = 0;
3533 if (s->tv_state) {
3534 if (s->tv_state->brightness != 0x32 || s->tv_state->contrast != 0x32 || s->tv_state->saturation != 0x32 ||
3535 s->tv_state->hue != 0x32) {
3536 s->bcsh_en = 1;
3537 }
3538 }
3539
3540 if (s->bcsh_en) {
3541 if (!s->yuv_overlay) {
3542 s->post_r2y_en = 1;
3543 }
3544 if (!is_yuv_output(s->bus_format)) {
3545 s->post_y2r_en = 1;
3546 }
3547 } else {
3548 if (!s->yuv_overlay && is_yuv_output(s->bus_format)) {
3549 s->post_r2y_en = 1;
3550 }
3551 if (s->yuv_overlay && !is_yuv_output(s->bus_format)) {
3552 s->post_y2r_en = 1;
3553 }
3554 }
3555
3556 s->post_csc_mode = to_vop_csc_mode(s->color_space);
3557 VOP_CTRL_SET(vop, bcsh_r2y_en, s->post_r2y_en);
3558 VOP_CTRL_SET(vop, bcsh_y2r_en, s->post_y2r_en);
3559 VOP_CTRL_SET(vop, bcsh_r2y_csc_mode, s->post_csc_mode);
3560 VOP_CTRL_SET(vop, bcsh_y2r_csc_mode, s->post_csc_mode);
3561 if (!s->bcsh_en) {
3562 VOP_CTRL_SET(vop, bcsh_en, s->bcsh_en);
3563 return;
3564 }
3565
3566 if (vop_data->feature & VOP_FEATURE_OUTPUT_10BIT) {
3567 brightness = interpolate(0, -0x80, 0x64, 0x7f, s->tv_state->brightness);
3568 } else if (VOP_MAJOR(vop->version) == 0x2 && VOP_MINOR(vop->version) == 0x6) { /* px30 vopb */
3569 brightness = interpolate(0, -0x40, 0x64, 0x3f, s->tv_state->brightness);
3570 } else {
3571 brightness = interpolate(0, -0x20, 0x64, 0x1f, s->tv_state->brightness);
3572 }
3573
3574 if ((VOP_MAJOR(vop->version) == 0x3) ||
3575 (VOP_MAJOR(vop->version) == 0x2 && VOP_MINOR(vop->version) == 0x6)) { /* px30 vopb */
3576 contrast = interpolate(0, 0, 0x64, 0x1ff, s->tv_state->contrast);
3577 saturation = interpolate(0, 0, 0x64, 0x1ff, s->tv_state->saturation);
3578 /*
3579 * a:[-30~0]:
3580 * sin_hue = 0x100 - sin(a)*256;
3581 * cos_hue = cos(a)*256;
3582 * a:[0~30]
3583 * sin_hue = sin(a)*256;
3584 * cos_hue = cos(a)*256;
3585 */
3586 hue = interpolate(0, -0x1e, 0x64, 0x1e, s->tv_state->hue);
3587 sin_hue = fixp_sin32(hue) >> 0x17;
3588 cos_hue = fixp_cos32(hue) >> 0x17;
3589 VOP_CTRL_SET(vop, bcsh_sat_con, saturation * contrast / 0x100);
3590 } else {
3591 contrast = interpolate(0, 0, 0x64, 0xff, s->tv_state->contrast);
3592 saturation = interpolate(0, 0, 0x64, 0xff, s->tv_state->saturation);
3593 /*
3594 * a:[-30~0]:
3595 * sin_hue = 0x100 - sin(a)*128;
3596 * cos_hue = cos(a)*128;
3597 * a:[0~30]
3598 * sin_hue = sin(a)*128;
3599 * cos_hue = cos(a)*128;
3600 */
3601 hue = interpolate(0, -0x1e, 0x64, 0x1e, s->tv_state->hue);
3602 sin_hue = fixp_sin32(hue) >> 0x18;
3603 cos_hue = fixp_cos32(hue) >> 0x18;
3604 VOP_CTRL_SET(vop, bcsh_sat_con, saturation * contrast / 0x80);
3605 }
3606
3607 VOP_CTRL_SET(vop, bcsh_brightness, brightness);
3608 VOP_CTRL_SET(vop, bcsh_contrast, contrast);
3609 VOP_CTRL_SET(vop, bcsh_sin_hue, sin_hue);
3610 VOP_CTRL_SET(vop, bcsh_cos_hue, cos_hue);
3611 VOP_CTRL_SET(vop, bcsh_out_mode, BCSH_OUT_MODE_NORMAL_VIDEO);
3612 if (VOP_MAJOR(vop->version) == 0x3 && VOP_MINOR(vop->version) == 0) {
3613 VOP_CTRL_SET(vop, auto_gate_en, 0);
3614 }
3615 VOP_CTRL_SET(vop, bcsh_en, s->bcsh_en);
3616 }
3617
vop_cfg_update(struct drm_crtc * crtc,struct drm_crtc_state * old_crtc_state)3618 static void vop_cfg_update(struct drm_crtc *crtc, struct drm_crtc_state *old_crtc_state)
3619 {
3620 struct rockchip_crtc_state *s = to_rockchip_crtc_state(crtc->state);
3621 struct vop *vop = to_vop(crtc);
3622 const struct vop_data *vop_data = vop->data;
3623
3624 spin_lock(&vop->reg_lock);
3625
3626 vop_update_csc(crtc);
3627
3628 vop_tv_config_update(crtc, old_crtc_state);
3629
3630 if (s->afbdc_en) {
3631 u32 pic_size, pic_offset;
3632
3633 VOP_CTRL_SET(vop, afbdc_format, s->afbdc_win_format | 1 << 0x4);
3634 VOP_CTRL_SET(vop, afbdc_hreg_block_split, 0);
3635 VOP_CTRL_SET(vop, afbdc_sel, s->afbdc_win_id);
3636 VOP_CTRL_SET(vop, afbdc_hdr_ptr, s->afbdc_win_ptr);
3637 pic_size = (s->afbdc_win_width & 0xffff);
3638 pic_size |= s->afbdc_win_height << 0x10;
3639 VOP_CTRL_SET(vop, afbdc_pic_size, pic_size);
3640
3641 VOP_CTRL_SET(vop, afbdc_pic_vir_width, s->afbdc_win_vir_width);
3642 pic_offset = (s->afbdc_win_xoffset & 0xffff);
3643 pic_offset |= s->afbdc_win_yoffset << 0x10;
3644 VOP_CTRL_SET(vop, afbdc_pic_offset, pic_offset);
3645 }
3646
3647 VOP_CTRL_SET(vop, afbdc_en, s->afbdc_en);
3648
3649 VOP_CTRL_SET(vop, dsp_layer_sel, s->dsp_layer_sel);
3650 if (vop_data->feature & VOP_FEATURE_OVERSCAN) {
3651 vop_post_config(crtc);
3652 }
3653
3654 spin_unlock(&vop->reg_lock);
3655 }
3656
vop_fs_irq_is_pending(struct vop * vop)3657 static bool vop_fs_irq_is_pending(struct vop *vop)
3658 {
3659 if (VOP_MAJOR(vop->version) == 0x3 && VOP_MINOR(vop->version) >= 0x7) {
3660 return VOP_INTR_GET_TYPE(vop, status, FS_FIELD_INTR);
3661 } else {
3662 return VOP_INTR_GET_TYPE(vop, status, FS_INTR);
3663 }
3664 }
3665
vop_wait_for_irq_handler(struct vop * vop)3666 static void vop_wait_for_irq_handler(struct vop *vop)
3667 {
3668 bool pending;
3669 int ret;
3670
3671 /*
3672 * Spin until frame start interrupt status bit goes low, which means
3673 * that interrupt handler was invoked and cleared it. The timeout of
3674 * 10 msecs is really too long, but it is just a safety measure if
3675 * something goes really wrong. The wait will only happen in the very
3676 * unlikely case of a vblank happening exactly at the same time and
3677 * shouldn't exceed microseconds range.
3678 */
3679 ret = readx_poll_timeout_atomic(vop_fs_irq_is_pending, vop, pending, !pending, 0, 0xa * 0x3e8);
3680 if (ret) {
3681 DRM_DEV_ERROR(vop->dev, "VOP vblank IRQ stuck for 10 ms\n");
3682 }
3683
3684 synchronize_irq(vop->irq);
3685 }
3686
vop_crtc_atomic_flush(struct drm_crtc * crtc,struct drm_crtc_state * old_crtc_state)3687 static void vop_crtc_atomic_flush(struct drm_crtc *crtc, struct drm_crtc_state *old_crtc_state)
3688 {
3689 struct drm_atomic_state *old_state = old_crtc_state->state;
3690 struct drm_plane_state *old_plane_state;
3691 struct vop *vop = to_vop(crtc);
3692 struct drm_plane *plane;
3693 int i;
3694 unsigned long flags;
3695 struct rockchip_crtc_state *s = to_rockchip_crtc_state(crtc->state);
3696
3697 vop_cfg_update(crtc, old_crtc_state);
3698
3699 if (!vop->is_iommu_enabled && vop->is_iommu_needed) {
3700 int ret;
3701
3702 if (s->mode_update) {
3703 VOP_CTRL_SET(vop, dma_stop, 1);
3704 }
3705
3706 ret = rockchip_drm_dma_attach_device(vop->drm_dev, vop->dev);
3707 if (ret) {
3708 vop->is_iommu_enabled = false;
3709 vop_disable_all_planes(vop);
3710 dev_err(vop->dev, "failed to attach dma mapping, %d\n", ret);
3711 } else {
3712 vop->is_iommu_enabled = true;
3713 VOP_CTRL_SET(vop, dma_stop, 0);
3714 }
3715 }
3716
3717 vop_update_hdr(crtc, old_crtc_state);
3718 if (old_crtc_state->color_mgmt_changed || old_crtc_state->active_changed) {
3719 if (crtc->state->gamma_lut || vop->gamma_lut) {
3720 if (old_crtc_state->gamma_lut) {
3721 vop->gamma_lut = old_crtc_state->gamma_lut->data;
3722 }
3723 vop_crtc_atomic_gamma_set(crtc, old_crtc_state);
3724 }
3725 }
3726
3727 spin_lock_irqsave(&vop->irq_lock, flags);
3728 vop->pre_overlay = s->hdr.pre_overlay;
3729 vop_cfg_done(vop);
3730 /*
3731 * rk322x and rk332x odd-even field will mistake when in interlace mode.
3732 * we must switch to frame effect before switch screen and switch to
3733 * field effect after switch screen complete.
3734 */
3735 if (VOP_MAJOR(vop->version) == 0x3 && (VOP_MINOR(vop->version) == 0x7 || VOP_MINOR(vop->version) == 0x8)) {
3736 if (!s->mode_update && VOP_CTRL_GET(vop, reg_done_frm)) {
3737 VOP_CTRL_SET(vop, reg_done_frm, 0);
3738 }
3739 } else {
3740 VOP_CTRL_SET(vop, reg_done_frm, 0);
3741 }
3742 if (vop->mcu_timing.mcu_pix_total) {
3743 VOP_CTRL_SET(vop, mcu_hold_mode, 0);
3744 }
3745
3746 spin_unlock_irqrestore(&vop->irq_lock, flags);
3747
3748 /*
3749 * There is a (rather unlikely) possiblity that a vblank interrupt
3750 * fired before we set the cfg_done bit. To avoid spuriously
3751 * signalling flip completion we need to wait for it to finish.
3752 */
3753 vop_wait_for_irq_handler(vop);
3754
3755 spin_lock_irq(&crtc->dev->event_lock);
3756 if (crtc->state->event) {
3757 WARN_ON(drm_crtc_vblank_get(crtc) != 0);
3758 WARN_ON(vop->event);
3759
3760 vop->event = crtc->state->event;
3761 crtc->state->event = NULL;
3762 }
3763 spin_unlock_irq(&crtc->dev->event_lock);
3764 for_each_old_plane_in_state(old_state, plane, old_plane_state, i)
3765 {
3766 if (!old_plane_state->fb) {
3767 continue;
3768 }
3769
3770 if (old_plane_state->fb == plane->state->fb) {
3771 continue;
3772 }
3773
3774 drm_framebuffer_get(old_plane_state->fb);
3775 WARN_ON(drm_crtc_vblank_get(crtc) != 0);
3776 drm_flip_work_queue(&vop->fb_unref_work, old_plane_state->fb);
3777 set_bit(VOP_PENDING_FB_UNREF, &vop->pending);
3778 }
3779 }
3780
3781 static const struct drm_crtc_helper_funcs vop_crtc_helper_funcs = {
3782 .mode_fixup = vop_crtc_mode_fixup,
3783 .atomic_check = vop_crtc_atomic_check,
3784 .atomic_flush = vop_crtc_atomic_flush,
3785 .atomic_enable = vop_crtc_atomic_enable,
3786 .atomic_disable = vop_crtc_atomic_disable,
3787 };
3788
vop_crtc_destroy(struct drm_crtc * crtc)3789 static void vop_crtc_destroy(struct drm_crtc *crtc)
3790 {
3791 drm_crtc_cleanup(crtc);
3792 }
3793
vop_crtc_reset(struct drm_crtc * crtc)3794 static void vop_crtc_reset(struct drm_crtc *crtc)
3795 {
3796 struct rockchip_crtc_state *s = to_rockchip_crtc_state(crtc->state);
3797
3798 if (crtc->state) {
3799 __drm_atomic_helper_crtc_destroy_state(crtc->state);
3800 kfree(s);
3801 }
3802
3803 s = kzalloc(sizeof(*s), GFP_KERNEL);
3804 if (!s) {
3805 return;
3806 }
3807 crtc->state = &s->base;
3808 crtc->state->crtc = crtc;
3809
3810 s->left_margin = 0x64;
3811 s->right_margin = 0x64;
3812 s->top_margin = 0x64;
3813 s->bottom_margin = 0x64;
3814 }
3815
vop_crtc_duplicate_state(struct drm_crtc * crtc)3816 static struct drm_crtc_state *vop_crtc_duplicate_state(struct drm_crtc *crtc)
3817 {
3818 struct rockchip_crtc_state *rockchip_state, *old_state;
3819 if (WARN_ON(!crtc->state))
3820 return NULL;
3821
3822 old_state = to_rockchip_crtc_state(crtc->state);
3823 rockchip_state = kmemdup(old_state, sizeof(*old_state), GFP_KERNEL);
3824 if (!rockchip_state) {
3825 return NULL;
3826 }
3827
3828 __drm_atomic_helper_crtc_duplicate_state(crtc, &rockchip_state->base);
3829 return &rockchip_state->base;
3830 }
3831
vop_crtc_destroy_state(struct drm_crtc * crtc,struct drm_crtc_state * state)3832 static void vop_crtc_destroy_state(struct drm_crtc *crtc, struct drm_crtc_state *state)
3833 {
3834 struct rockchip_crtc_state *s = to_rockchip_crtc_state(state);
3835
3836 __drm_atomic_helper_crtc_destroy_state(&s->base);
3837 kfree(s);
3838 }
3839
3840 #ifdef CONFIG_DRM_ANALOGIX_DP
vop_get_edp_connector(struct vop * vop)3841 static struct drm_connector *vop_get_edp_connector(struct vop *vop)
3842 {
3843 struct drm_connector *connector;
3844 struct drm_connector_list_iter conn_iter;
3845
3846 drm_connector_list_iter_begin(vop->drm_dev, &conn_iter);
3847 drm_for_each_connector_iter(connector, &conn_iter)
3848 {
3849 if (connector->connector_type == DRM_MODE_CONNECTOR_eDP) {
3850 drm_connector_list_iter_end(&conn_iter);
3851 return connector;
3852 }
3853 }
3854 drm_connector_list_iter_end(&conn_iter);
3855
3856 return NULL;
3857 }
3858
vop_crtc_set_crc_source(struct drm_crtc * crtc,const char * source_name)3859 static int vop_crtc_set_crc_source(struct drm_crtc *crtc, const char *source_name)
3860 {
3861 struct vop *vop = to_vop(crtc);
3862 struct drm_connector *connector;
3863 int ret;
3864
3865 connector = vop_get_edp_connector(vop);
3866 if (!connector) {
3867 return -EINVAL;
3868 }
3869
3870 if (source_name && strcmp(source_name, "auto") == 0) {
3871 ret = analogix_dp_start_crc(connector);
3872 } else if (!source_name) {
3873 ret = analogix_dp_stop_crc(connector);
3874 } else {
3875 ret = -EINVAL;
3876 }
3877
3878 return ret;
3879 }
3880
vop_crtc_verify_crc_source(struct drm_crtc * crtc,const char * source_name,size_t * values_cnt)3881 static int vop_crtc_verify_crc_source(struct drm_crtc *crtc, const char *source_name, size_t *values_cnt)
3882 {
3883 if (source_name && strcmp(source_name, "auto") != 0) {
3884 return -EINVAL;
3885 }
3886
3887 *values_cnt = 0x3;
3888 return 0;
3889 }
3890
3891 #else
vop_crtc_set_crc_source(struct drm_crtc * crtc,const char * source_name)3892 static int vop_crtc_set_crc_source(struct drm_crtc *crtc, const char *source_name)
3893 {
3894 return -ENODEV;
3895 }
3896
vop_crtc_verify_crc_source(struct drm_crtc * crtc,const char * source_name,size_t * values_cnt)3897 static int vop_crtc_verify_crc_source(struct drm_crtc *crtc, const char *source_name, size_t *values_cnt)
3898 {
3899 return -ENODEV;
3900 }
3901 #endif
3902
vop_crtc_atomic_get_property(struct drm_crtc * crtc,const struct drm_crtc_state * state,struct drm_property * property,uint64_t * val)3903 static int vop_crtc_atomic_get_property(struct drm_crtc *crtc, const struct drm_crtc_state *state,
3904 struct drm_property *property, uint64_t *val)
3905 {
3906 struct drm_device *drm_dev = crtc->dev;
3907 struct rockchip_drm_private *private = drm_dev->dev_private;
3908 struct drm_mode_config *mode_config = &drm_dev->mode_config;
3909 struct rockchip_crtc_state *s = to_rockchip_crtc_state(state);
3910 struct vop *vop = to_vop(crtc);
3911
3912 if (property == mode_config->tv_left_margin_property) {
3913 *val = s->left_margin;
3914 return 0;
3915 }
3916
3917 if (property == mode_config->tv_right_margin_property) {
3918 *val = s->right_margin;
3919 return 0;
3920 }
3921
3922 if (property == mode_config->tv_top_margin_property) {
3923 *val = s->top_margin;
3924 return 0;
3925 }
3926
3927 if (property == mode_config->tv_bottom_margin_property) {
3928 *val = s->bottom_margin;
3929 return 0;
3930 }
3931
3932 if (property == private->aclk_prop) {
3933 /* KHZ, keep align with mode->clock */
3934 *val = clk_get_rate(vop->aclk) / 0x3e8;
3935 return 0;
3936 }
3937
3938 if (property == private->bg_prop) {
3939 *val = vop->background;
3940 return 0;
3941 }
3942
3943 if (property == private->line_flag_prop) {
3944 *val = vop->line_flag;
3945 return 0;
3946 }
3947
3948 DRM_ERROR("failed to get vop crtc property\n");
3949 return -EINVAL;
3950 }
3951
vop_crtc_atomic_set_property(struct drm_crtc * crtc,struct drm_crtc_state * state,struct drm_property * property,uint64_t val)3952 static int vop_crtc_atomic_set_property(struct drm_crtc *crtc, struct drm_crtc_state *state,
3953 struct drm_property *property, uint64_t val)
3954 {
3955 struct drm_device *drm_dev = crtc->dev;
3956 struct rockchip_drm_private *private = drm_dev->dev_private;
3957 struct drm_mode_config *mode_config = &drm_dev->mode_config;
3958 struct rockchip_crtc_state *s = to_rockchip_crtc_state(state);
3959 struct vop *vop = to_vop(crtc);
3960
3961 if (property == mode_config->tv_left_margin_property) {
3962 s->left_margin = val;
3963 return 0;
3964 }
3965
3966 if (property == mode_config->tv_right_margin_property) {
3967 s->right_margin = val;
3968 return 0;
3969 }
3970
3971 if (property == mode_config->tv_top_margin_property) {
3972 s->top_margin = val;
3973 return 0;
3974 }
3975
3976 if (property == mode_config->tv_bottom_margin_property) {
3977 s->bottom_margin = val;
3978 return 0;
3979 }
3980
3981 if (property == private->bg_prop) {
3982 vop->background = val;
3983 return 0;
3984 }
3985
3986 if (property == private->line_flag_prop) {
3987 vop->line_flag = val;
3988 return 0;
3989 }
3990
3991 DRM_ERROR("failed to set vop crtc property\n");
3992 return -EINVAL;
3993 }
3994
3995 static const struct drm_crtc_funcs vop_crtc_funcs = {
3996 .gamma_set = vop_crtc_legacy_gamma_set,
3997 .set_config = drm_atomic_helper_set_config,
3998 .page_flip = drm_atomic_helper_page_flip,
3999 .destroy = vop_crtc_destroy,
4000 .reset = vop_crtc_reset,
4001 .atomic_get_property = vop_crtc_atomic_get_property,
4002 .atomic_set_property = vop_crtc_atomic_set_property,
4003 .atomic_duplicate_state = vop_crtc_duplicate_state,
4004 .atomic_destroy_state = vop_crtc_destroy_state,
4005 .enable_vblank = vop_crtc_enable_vblank,
4006 .disable_vblank = vop_crtc_disable_vblank,
4007 .set_crc_source = vop_crtc_set_crc_source,
4008 .verify_crc_source = vop_crtc_verify_crc_source,
4009 };
4010
vop_fb_unref_worker(struct drm_flip_work * work,void * val)4011 static void vop_fb_unref_worker(struct drm_flip_work *work, void *val)
4012 {
4013 struct vop *vop = container_of(work, struct vop, fb_unref_work);
4014 struct drm_framebuffer *fb = val;
4015
4016 drm_crtc_vblank_put(&vop->rockchip_crtc.crtc);
4017 drm_framebuffer_put(fb);
4018 }
4019
vop_handle_vblank(struct vop * vop)4020 static void vop_handle_vblank(struct vop *vop)
4021 {
4022 struct drm_device *drm = vop->drm_dev;
4023 struct drm_crtc *crtc = &vop->rockchip_crtc.crtc;
4024 unsigned long flags;
4025
4026 spin_lock_irqsave(&drm->event_lock, flags);
4027 if (vop->event) {
4028 drm_crtc_send_vblank_event(crtc, vop->event);
4029 drm_crtc_vblank_put(crtc);
4030 vop->event = NULL;
4031 }
4032 spin_unlock_irqrestore(&drm->event_lock, flags);
4033
4034 if (test_and_clear_bit(VOP_PENDING_FB_UNREF, &vop->pending)) {
4035 drm_flip_work_commit(&vop->fb_unref_work, system_unbound_wq);
4036 }
4037 }
4038
vop_isr(int irq,void * data)4039 static irqreturn_t vop_isr(int irq, void *data)
4040 {
4041 struct vop *vop = data;
4042 struct drm_crtc *crtc = &vop->rockchip_crtc.crtc;
4043 uint32_t active_irqs;
4044 unsigned long flags;
4045 int ret = IRQ_NONE;
4046
4047 /*
4048 * The irq is shared with the iommu. If the runtime-pm state of the
4049 * vop-device is disabled the irq has to be targeted at the iommu.
4050 */
4051 if (!pm_runtime_get_if_in_use(vop->dev)) {
4052 return IRQ_NONE;
4053 }
4054
4055 if (vop_core_clks_enable(vop)) {
4056 DRM_DEV_ERROR_RATELIMITED(vop->dev, "couldn't enable clocks\n");
4057 goto out;
4058 }
4059
4060 /*
4061 * interrupt register has interrupt status, enable and clear bits, we
4062 * must hold irq_lock to avoid a race with enable/disable_vblank().
4063 */
4064 spin_lock_irqsave(&vop->irq_lock, flags);
4065
4066 active_irqs = VOP_INTR_GET_TYPE(vop, status, INTR_MASK);
4067 /* Clear all active interrupt sources */
4068 if (active_irqs) {
4069 VOP_INTR_SET_TYPE(vop, clear, active_irqs, 1);
4070 }
4071
4072 spin_unlock_irqrestore(&vop->irq_lock, flags);
4073
4074 /* This is expected for vop iommu irqs, since the irq is shared */
4075 if (!active_irqs) {
4076 goto out_disable;
4077 }
4078
4079 if (active_irqs & DSP_HOLD_VALID_INTR) {
4080 complete(&vop->dsp_hold_completion);
4081 active_irqs &= ~DSP_HOLD_VALID_INTR;
4082 ret = IRQ_HANDLED;
4083 }
4084
4085 if (active_irqs & LINE_FLAG_INTR) {
4086 complete(&vop->line_flag_completion);
4087 active_irqs &= ~LINE_FLAG_INTR;
4088 ret = IRQ_HANDLED;
4089 }
4090
4091 if ((active_irqs & FS_INTR) || (active_irqs & FS_FIELD_INTR)) {
4092 /* This is IC design not reasonable, this two register bit need
4093 * frame effective, but actually it's effective immediately, so
4094 * we config this register at frame start.
4095 */
4096 spin_lock_irqsave(&vop->irq_lock, flags);
4097 VOP_CTRL_SET(vop, level2_overlay_en, vop->pre_overlay);
4098 VOP_CTRL_SET(vop, alpha_hard_calc, vop->pre_overlay);
4099 spin_unlock_irqrestore(&vop->irq_lock, flags);
4100 drm_crtc_handle_vblank(crtc);
4101 vop_handle_vblank(vop);
4102 active_irqs &= ~(FS_INTR | FS_FIELD_INTR);
4103 ret = IRQ_HANDLED;
4104 }
4105
4106 #define ERROR_HANDLER(x, val) \
4107 do { \
4108 if (active_irqs & x##_INTR) { \
4109 DRM_DEV_ERROR_RATELIMITED(val, #x " irq err\n"); \
4110 active_irqs &= ~x##_INTR; \
4111 ret = IRQ_HANDLED; \
4112 } \
4113 } while (0)
4114
4115 ERROR_HANDLER(BUS_ERROR, vop->dev);
4116 ERROR_HANDLER(WIN0_EMPTY, vop->dev);
4117 ERROR_HANDLER(WIN1_EMPTY, vop->dev);
4118 ERROR_HANDLER(WIN2_EMPTY, vop->dev);
4119 ERROR_HANDLER(WIN3_EMPTY, vop->dev);
4120 ERROR_HANDLER(HWC_EMPTY, vop->dev);
4121 ERROR_HANDLER(POST_BUF_EMPTY, vop->dev);
4122
4123 /* Unhandled irqs are spurious. */
4124 if (active_irqs) {
4125 DRM_ERROR("Unknown VOP IRQs: %#02x\n", active_irqs);
4126 }
4127
4128 out_disable:
4129 vop_core_clks_disable(vop);
4130 out:
4131 pm_runtime_put(vop->dev);
4132 return ret;
4133 }
4134
vop_plane_add_properties(struct vop * vop,struct drm_plane * plane,const struct vop_win * win)4135 static void vop_plane_add_properties(struct vop *vop, struct drm_plane *plane, const struct vop_win *win)
4136 {
4137 unsigned int flags = 0;
4138
4139 flags |= (VOP_WIN_SUPPORT(vop, win, xmirror)) ? DRM_MODE_REFLECT_X : 0;
4140 flags |= (VOP_WIN_SUPPORT(vop, win, ymirror)) ? DRM_MODE_REFLECT_Y : 0;
4141 if (flags) {
4142 drm_plane_create_rotation_property(plane, DRM_MODE_ROTATE_0, DRM_MODE_ROTATE_0 | flags);
4143 }
4144 }
4145
vop_plane_create_name_property(struct vop * vop,struct vop_win * win)4146 static int vop_plane_create_name_property(struct vop *vop, struct vop_win *win)
4147 {
4148 struct drm_prop_enum_list *props = vop->plane_name_list;
4149 struct drm_property *prop;
4150 uint64_t bits = BIT_ULL(win->plane_id);
4151
4152 prop = drm_property_create_bitmask(vop->drm_dev, DRM_MODE_PROP_IMMUTABLE, "NAME", props, vop->num_wins, bits);
4153 if (!prop) {
4154 DRM_DEV_ERROR(vop->dev, "create Name prop for %s failed\n", win->name);
4155 return -ENOMEM;
4156 }
4157 win->name_prop = prop;
4158 drm_object_attach_property(&win->base.base, win->name_prop, bits);
4159
4160 return 0;
4161 }
4162
vop_plane_init(struct vop * vop,struct vop_win * win,unsigned long possible_crtcs)4163 static int vop_plane_init(struct vop *vop, struct vop_win *win, unsigned long possible_crtcs)
4164 {
4165 struct rockchip_drm_private *private = vop->drm_dev->dev_private;
4166 unsigned int blend_caps =
4167 BIT(DRM_MODE_BLEND_PIXEL_NONE) | BIT(DRM_MODE_BLEND_PREMULTI) | BIT(DRM_MODE_BLEND_COVERAGE);
4168 const struct vop_data *vop_data = vop->data;
4169 uint64_t feature = 0;
4170 int ret;
4171
4172 ret = drm_universal_plane_init(vop->drm_dev, &win->base, possible_crtcs, &vop_plane_funcs, win->data_formats,
4173 win->nformats, win->format_modifiers, win->type, win->name);
4174 if (ret) {
4175 DRM_ERROR("failed to initialize plane %d\n", ret);
4176 return ret;
4177 }
4178 drm_plane_helper_add(&win->base, &plane_helper_funcs);
4179
4180 if (win->phy->scl) {
4181 feature |= BIT(ROCKCHIP_DRM_PLANE_FEATURE_SCALE);
4182 }
4183 if (VOP_WIN_SUPPORT(vop, win, src_alpha_ctl) || VOP_WIN_SUPPORT(vop, win, alpha_en)) {
4184 feature |= BIT(ROCKCHIP_DRM_PLANE_FEATURE_ALPHA);
4185 }
4186 if (win->feature & WIN_FEATURE_HDR2SDR) {
4187 feature |= BIT(ROCKCHIP_DRM_PLANE_FEATURE_HDR2SDR);
4188 }
4189 if (win->feature & WIN_FEATURE_SDR2HDR) {
4190 feature |= BIT(ROCKCHIP_DRM_PLANE_FEATURE_SDR2HDR);
4191 }
4192 if (win->feature & WIN_FEATURE_AFBDC) {
4193 feature |= BIT(ROCKCHIP_DRM_PLANE_FEATURE_AFBDC);
4194 }
4195
4196 drm_object_attach_property(&win->base.base, vop->plane_feature_prop, feature);
4197 drm_object_attach_property(&win->base.base, private->eotf_prop, 0);
4198 drm_object_attach_property(&win->base.base, private->color_space_prop, 0);
4199 if (VOP_WIN_SUPPORT(vop, win, global_alpha_val)) {
4200 drm_plane_create_alpha_property(&win->base);
4201 }
4202 drm_object_attach_property(&win->base.base, private->async_commit_prop, 0);
4203
4204 if (win->parent) {
4205 drm_object_attach_property(&win->base.base, private->share_id_prop, win->parent->base.base.id);
4206 } else {
4207 drm_object_attach_property(&win->base.base, private->share_id_prop, win->base.base.id);
4208 }
4209
4210 drm_plane_create_blend_mode_property(&win->base, blend_caps);
4211 drm_plane_create_zpos_property(&win->base, win->win_id, 0, vop->num_wins - 1);
4212 vop_plane_create_name_property(vop, win);
4213
4214 win->input_width_prop =
4215 drm_property_create_range(vop->drm_dev, DRM_MODE_PROP_IMMUTABLE, "INPUT_WIDTH", 0, vop_data->max_input.width);
4216 win->input_height_prop =
4217 drm_property_create_range(vop->drm_dev, DRM_MODE_PROP_IMMUTABLE, "INPUT_HEIGHT", 0, vop_data->max_input.height);
4218
4219 win->output_width_prop =
4220 drm_property_create_range(vop->drm_dev, DRM_MODE_PROP_IMMUTABLE, "OUTPUT_WIDTH", 0, vop_data->max_input.width);
4221 win->output_height_prop = drm_property_create_range(vop->drm_dev, DRM_MODE_PROP_IMMUTABLE, "OUTPUT_HEIGHT", 0,
4222 vop_data->max_input.height);
4223
4224 win->scale_prop = drm_property_create_range(vop->drm_dev, DRM_MODE_PROP_IMMUTABLE, "SCALE_RATE", 0x8, 0x8);
4225 /*
4226 * Support 24 bit(RGB888) or 16 bit(rgb565) color key.
4227 * Bit 31 is used as a flag to disable (0) or enable
4228 * color keying (1).
4229 */
4230 win->color_key_prop = drm_property_create_range(vop->drm_dev, 0, "colorkey", 0, 0x80ffffff);
4231 if (!win->input_width_prop || !win->input_height_prop || !win->scale_prop || !win->color_key_prop) {
4232 DRM_ERROR("failed to create property\n");
4233 return -ENOMEM;
4234 }
4235
4236 drm_object_attach_property(&win->base.base, win->input_width_prop, 0);
4237 drm_object_attach_property(&win->base.base, win->input_height_prop, 0);
4238 drm_object_attach_property(&win->base.base, win->output_width_prop, 0);
4239 drm_object_attach_property(&win->base.base, win->output_height_prop, 0);
4240 drm_object_attach_property(&win->base.base, win->scale_prop, 0);
4241 drm_object_attach_property(&win->base.base, win->color_key_prop, 0);
4242
4243 return 0;
4244 }
4245
vop_of_init_display_lut(struct vop * vop)4246 static int vop_of_init_display_lut(struct vop *vop)
4247 {
4248 struct device_node *node = vop->dev->of_node;
4249 struct device_node *dsp_lut;
4250 u32 lut_len = vop->lut_len;
4251 struct property *prop;
4252 int length, i, j;
4253 int ret;
4254
4255 if (!vop->lut) {
4256 return -ENOMEM;
4257 }
4258
4259 dsp_lut = of_parse_phandle(node, "dsp-lut", 0);
4260 if (!dsp_lut) {
4261 return -ENXIO;
4262 }
4263
4264 prop = of_find_property(dsp_lut, "gamma-lut", &length);
4265 if (!prop) {
4266 dev_err(vop->dev, "failed to find gamma_lut\n");
4267 return -ENXIO;
4268 }
4269
4270 length >>= 0x2;
4271
4272 if (length != lut_len) {
4273 u32 r, g, b;
4274 u32 *lut = kmalloc_array(length, sizeof(*lut), GFP_KERNEL);
4275
4276 if (!lut) {
4277 return -ENOMEM;
4278 }
4279 ret = of_property_read_u32_array(dsp_lut, "gamma-lut", lut, length);
4280 if (ret) {
4281 dev_err(vop->dev, "load gamma-lut failed\n");
4282 kfree(lut);
4283 return -EINVAL;
4284 }
4285
4286 if (lut_len == 0 || length == 0) {
4287 return -EPERM;
4288 }
4289 for (i = 0; i < lut_len; i++) {
4290 j = i * length / lut_len;
4291 r = lut[j] / length / length * lut_len / length;
4292 g = lut[j] / length % length * lut_len / length;
4293 b = lut[j] % length * lut_len / length;
4294
4295 vop->lut[i] = r * lut_len * lut_len + g * lut_len + b;
4296 }
4297
4298 kfree(lut);
4299 } else {
4300 of_property_read_u32_array(dsp_lut, "gamma-lut", vop->lut, vop->lut_len);
4301 }
4302 vop->lut_active = true;
4303
4304 return 0;
4305 }
4306
vop_crtc_create_plane_mask_property(struct vop * vop,struct drm_crtc * crtc)4307 static int vop_crtc_create_plane_mask_property(struct vop *vop, struct drm_crtc *crtc)
4308 {
4309 struct drm_property *prop;
4310
4311 static const struct drm_prop_enum_list props[] = {
4312 {ROCKCHIP_VOP_WIN0, "Win0"},
4313 {ROCKCHIP_VOP_WIN1, "Win1"},
4314 {ROCKCHIP_VOP_WIN2, "Win2"},
4315 {ROCKCHIP_VOP_WIN3, "Win3"},
4316 };
4317
4318 prop = drm_property_create_bitmask(vop->drm_dev, DRM_MODE_PROP_IMMUTABLE, "PLANE_MASK", props, ARRAY_SIZE(props),
4319 0xffffffff);
4320 if (!prop) {
4321 DRM_DEV_ERROR(vop->dev, "create plane_mask prop for vp%d failed\n", vop->id);
4322 return -ENOMEM;
4323 }
4324
4325 vop->plane_mask_prop = prop;
4326 drm_object_attach_property(&crtc->base, vop->plane_mask_prop, vop->plane_mask);
4327
4328 return 0;
4329 }
4330
vop_crtc_create_feature_property(struct vop * vop,struct drm_crtc * crtc)4331 static int vop_crtc_create_feature_property(struct vop *vop, struct drm_crtc *crtc)
4332 {
4333 const struct vop_data *vop_data = vop->data;
4334
4335 struct drm_property *prop;
4336 u64 feature = 0;
4337
4338 static const struct drm_prop_enum_list props[] = {
4339 {ROCKCHIP_DRM_CRTC_FEATURE_ALPHA_SCALE, "ALPHA_SCALE"},
4340 {ROCKCHIP_DRM_CRTC_FEATURE_HDR10, "HDR10"},
4341 {ROCKCHIP_DRM_CRTC_FEATURE_NEXT_HDR, "NEXT_HDR"},
4342 };
4343
4344 if (vop_data->feature & VOP_FEATURE_ALPHA_SCALE) {
4345 feature |= BIT(ROCKCHIP_DRM_CRTC_FEATURE_ALPHA_SCALE);
4346 }
4347 if (vop_data->feature & VOP_FEATURE_HDR10) {
4348 feature |= BIT(ROCKCHIP_DRM_CRTC_FEATURE_HDR10);
4349 }
4350 if (vop_data->feature & VOP_FEATURE_NEXT_HDR) {
4351 feature |= BIT(ROCKCHIP_DRM_CRTC_FEATURE_NEXT_HDR);
4352 }
4353
4354 prop = drm_property_create_bitmask(vop->drm_dev, DRM_MODE_PROP_IMMUTABLE, "FEATURE", props, ARRAY_SIZE(props),
4355 0xffffffff);
4356 if (!prop) {
4357 DRM_DEV_ERROR(vop->dev, "create FEATURE prop for vop%d failed\n", vop->id);
4358 return -ENOMEM;
4359 }
4360
4361 vop->feature_prop = prop;
4362 drm_object_attach_property(&crtc->base, vop->feature_prop, feature);
4363
4364 return 0;
4365 }
4366
vop_create_crtc(struct vop * vop)4367 static int vop_create_crtc(struct vop *vop)
4368 {
4369 struct device *dev = vop->dev;
4370 struct drm_device *drm_dev = vop->drm_dev;
4371 struct rockchip_drm_private *private = drm_dev->dev_private;
4372 struct drm_plane *primary = NULL, *cursor = NULL, *plane, *tmp;
4373 struct drm_crtc *crtc = &vop->rockchip_crtc.crtc;
4374 struct device_node *port;
4375 int ret = 0;
4376 int i;
4377
4378 /*
4379 * Create drm_plane for primary and cursor planes first, since we need
4380 * to pass them to drm_crtc_init_with_planes, which sets the
4381 * "possible_crtcs" to the newly initialized crtc.
4382 */
4383 for (i = 0; i < vop->num_wins; i++) {
4384 struct vop_win *win = &vop->win[i];
4385
4386 if (win->type != DRM_PLANE_TYPE_PRIMARY && win->type != DRM_PLANE_TYPE_CURSOR) {
4387 continue;
4388 }
4389
4390 if (vop_plane_init(vop, win, 0)) {
4391 DRM_DEV_ERROR(vop->dev, "failed to init plane\n");
4392 goto err_cleanup_planes;
4393 }
4394
4395 plane = &win->base;
4396 if (plane->type == DRM_PLANE_TYPE_PRIMARY) {
4397 primary = plane;
4398 } else if (plane->type == DRM_PLANE_TYPE_CURSOR) {
4399 cursor = plane;
4400 }
4401 }
4402
4403 ret = drm_crtc_init_with_planes(drm_dev, crtc, primary, cursor, &vop_crtc_funcs, NULL);
4404 if (ret) {
4405 goto err_cleanup_planes;
4406 }
4407
4408 drm_crtc_helper_add(crtc, &vop_crtc_helper_funcs);
4409
4410 /*
4411 * Create drm_planes for overlay windows with possible_crtcs restricted
4412 * to the newly created crtc.
4413 */
4414 for (i = 0; i < vop->num_wins; i++) {
4415 struct vop_win *win = &vop->win[i];
4416 unsigned long possible_crtcs = drm_crtc_mask(crtc);
4417
4418 if (win->type != DRM_PLANE_TYPE_OVERLAY) {
4419 continue;
4420 }
4421
4422 if (vop_plane_init(vop, win, possible_crtcs)) {
4423 DRM_DEV_ERROR(vop->dev, "failed to init overlay\n");
4424 goto err_cleanup_crtc;
4425 }
4426 vop_plane_add_properties(vop, &win->base, win);
4427 }
4428
4429 port = of_get_child_by_name(dev->of_node, "port");
4430 if (!port) {
4431 DRM_DEV_ERROR(vop->dev, "no port node found in %pOF\n", dev->of_node);
4432 ret = -ENOENT;
4433 goto err_cleanup_crtc;
4434 }
4435
4436 drm_flip_work_init(&vop->fb_unref_work, "fb_unref", vop_fb_unref_worker);
4437
4438 init_completion(&vop->dsp_hold_completion);
4439 init_completion(&vop->line_flag_completion);
4440 crtc->port = port;
4441 rockchip_register_crtc_funcs(crtc, &private_crtc_funcs);
4442
4443 drm_object_attach_property(&crtc->base, private->soc_id_prop, vop->soc_id);
4444 drm_object_attach_property(&crtc->base, private->port_id_prop, vop->id);
4445 drm_object_attach_property(&crtc->base, private->aclk_prop, 0);
4446 drm_object_attach_property(&crtc->base, private->bg_prop, 0);
4447 drm_object_attach_property(&crtc->base, private->line_flag_prop, 0);
4448
4449 #define VOP_ATTACH_MODE_CONFIG_PROP(prop, v) drm_object_attach_property(&crtc->base, drm_dev->mode_config.prop, v)
4450
4451 VOP_ATTACH_MODE_CONFIG_PROP(tv_left_margin_property, 0x64);
4452 VOP_ATTACH_MODE_CONFIG_PROP(tv_right_margin_property, 0x64);
4453 VOP_ATTACH_MODE_CONFIG_PROP(tv_top_margin_property, 0x64);
4454 VOP_ATTACH_MODE_CONFIG_PROP(tv_bottom_margin_property, 0x64);
4455 #undef VOP_ATTACH_MODE_CONFIG_PROP
4456 vop_crtc_create_plane_mask_property(vop, crtc);
4457 vop_crtc_create_feature_property(vop, crtc);
4458
4459 if (vop->lut_regs) {
4460 u16 *r_base, *g_base, *b_base;
4461 u32 lut_len = vop->lut_len;
4462
4463 vop->lut = devm_kmalloc_array(dev, lut_len, sizeof(*vop->lut), GFP_KERNEL);
4464 if (!vop->lut) {
4465 goto err_unregister_crtc_funcs;
4466 }
4467
4468 if (vop_of_init_display_lut(vop)) {
4469 for (i = 0; i < lut_len; i++) {
4470 u32 r = i * lut_len * lut_len;
4471 u32 g = i * lut_len;
4472 u32 b = i;
4473
4474 vop->lut[i] = r | g | b;
4475 }
4476 }
4477
4478 drm_mode_crtc_set_gamma_size(crtc, lut_len);
4479 drm_crtc_enable_color_mgmt(crtc, 0, false, lut_len);
4480 r_base = crtc->gamma_store;
4481 g_base = r_base + crtc->gamma_size;
4482 b_base = g_base + crtc->gamma_size;
4483
4484 for (i = 0; i < lut_len; i++) {
4485 rockchip_vop_crtc_fb_gamma_get(crtc, &r_base[i], &g_base[i], &b_base[i], i);
4486 }
4487 }
4488 return 0;
4489
4490 err_unregister_crtc_funcs:
4491 rockchip_unregister_crtc_funcs(crtc);
4492 err_cleanup_crtc:
4493 drm_crtc_cleanup(crtc);
4494 err_cleanup_planes:
4495 list_for_each_entry_safe(plane, tmp, &drm_dev->mode_config.plane_list, head) drm_plane_cleanup(plane);
4496 return ret;
4497 }
4498
vop_destroy_crtc(struct vop * vop)4499 static void vop_destroy_crtc(struct vop *vop)
4500 {
4501 struct drm_crtc *crtc = &vop->rockchip_crtc.crtc;
4502 struct drm_device *drm_dev = vop->drm_dev;
4503 struct drm_plane *plane, *tmp;
4504
4505 of_node_put(crtc->port);
4506
4507 /*
4508 * We need to cleanup the planes now. Why?
4509 *
4510 * The planes are "&vop->win[i].base". That means the memory is
4511 * all part of the big "struct vop" chunk of memory. That memory
4512 * was devm allocated and associated with this component. We need to
4513 * free it ourselves before vop_unbind() finishes.
4514 */
4515 list_for_each_entry_safe(plane, tmp, &drm_dev->mode_config.plane_list, head) vop_plane_destroy(plane);
4516
4517 /*
4518 * Destroy CRTC after vop_plane_destroy() since vop_disable_plane()
4519 * references the CRTC.
4520 */
4521 drm_crtc_cleanup(crtc);
4522 drm_flip_work_cleanup(&vop->fb_unref_work);
4523 }
4524
4525 /*
4526 * Win_id is the order in vop_win_data array.
4527 * This is related to the actual hardware plane.
4528 * But in the Linux platform, such as video hardware and camera preview,
4529 * it can only be played on the nv12 plane.
4530 * So set the order of zpos to PRIMARY < OVERLAY (if have) < CURSOR (if have).
4531 */
vop_plane_get_zpos(enum drm_plane_type type,unsigned int size)4532 static int vop_plane_get_zpos(enum drm_plane_type type, unsigned int size)
4533 {
4534 switch (type) {
4535 case DRM_PLANE_TYPE_PRIMARY:
4536 return 0;
4537 case DRM_PLANE_TYPE_OVERLAY:
4538 return 1;
4539 case DRM_PLANE_TYPE_CURSOR:
4540 return size - 1;
4541 }
4542 return 0;
4543 }
4544
4545 /*
4546 * Initialize the vop->win array elements.
4547 */
vop_win_init(struct vop * vop)4548 static int vop_win_init(struct vop *vop)
4549 {
4550 const struct vop_data *vop_data = vop->data;
4551 unsigned int i, j, ret;
4552 unsigned int num_wins = 0;
4553 char name[DRM_PROP_NAME_LEN];
4554 uint8_t plane_id = 0;
4555 struct drm_prop_enum_list *plane_name_list;
4556 static const struct drm_prop_enum_list props[] = {
4557 {ROCKCHIP_DRM_PLANE_FEATURE_SCALE, "scale"}, {ROCKCHIP_DRM_PLANE_FEATURE_ALPHA, "alpha"},
4558 {ROCKCHIP_DRM_PLANE_FEATURE_HDR2SDR, "hdr2sdr"}, {ROCKCHIP_DRM_PLANE_FEATURE_SDR2HDR, "sdr2hdr"},
4559 {ROCKCHIP_DRM_PLANE_FEATURE_AFBDC, "afbdc"},
4560 };
4561
4562 for (i = 0; i < vop_data->win_size; i++) {
4563 struct vop_win *vop_win = &vop->win[num_wins];
4564 const struct vop_win_data *win_data = &vop_data->win[i];
4565
4566 if (!win_data->phy) {
4567 continue;
4568 }
4569
4570 vop_win->phy = win_data->phy;
4571 vop_win->csc = win_data->csc;
4572 vop_win->offset = win_data->base;
4573 vop_win->type = win_data->type;
4574 vop_win->data_formats = win_data->phy->data_formats;
4575 vop_win->nformats = win_data->phy->nformats;
4576 vop_win->format_modifiers = win_data->format_modifiers;
4577 vop_win->feature = win_data->feature;
4578 vop_win->vop = vop;
4579 vop_win->win_id = i;
4580 vop_win->area_id = 0;
4581 vop_win->plane_id = plane_id++;
4582 ret = snprintf(name, sizeof(name), "VOP%d-win%d-%d", vop->id, vop_win->win_id, vop_win->area_id);
4583 vop_win->name = devm_kstrdup(vop->dev, name, GFP_KERNEL);
4584 vop_win->zpos = vop_plane_get_zpos(win_data->type, vop_data->win_size);
4585
4586 num_wins++;
4587
4588 if (!vop->support_multi_area) {
4589 continue;
4590 }
4591
4592 for (j = 0; j < win_data->area_size; j++) {
4593 struct vop_win *vop_area = &vop->win[num_wins];
4594 const struct vop_win_phy *area = win_data->area[j];
4595
4596 vop_area->parent = vop_win;
4597 vop_area->offset = vop_win->offset;
4598 vop_area->phy = area;
4599 vop_area->type = DRM_PLANE_TYPE_OVERLAY;
4600 vop_area->data_formats = vop_win->data_formats;
4601 vop_area->nformats = vop_win->nformats;
4602 vop_area->format_modifiers = win_data->format_modifiers;
4603 vop_area->vop = vop;
4604 vop_area->win_id = i;
4605 vop_area->area_id = j + 1;
4606 vop_area->plane_id = plane_id++;
4607 ret = snprintf(name, sizeof(name), "VOP%d-win%d-%d", vop->id, vop_area->win_id, vop_area->area_id);
4608 vop_area->name = devm_kstrdup(vop->dev, name, GFP_KERNEL);
4609 num_wins++;
4610 }
4611 vop->plane_mask |= BIT(vop_win->win_id);
4612 }
4613
4614 vop->num_wins = num_wins;
4615
4616 vop->plane_feature_prop = drm_property_create_bitmask(
4617 vop->drm_dev, DRM_MODE_PROP_IMMUTABLE, "FEATURE", props, ARRAY_SIZE(props),
4618 BIT(ROCKCHIP_DRM_PLANE_FEATURE_SCALE) | BIT(ROCKCHIP_DRM_PLANE_FEATURE_ALPHA) |
4619 BIT(ROCKCHIP_DRM_PLANE_FEATURE_HDR2SDR) | BIT(ROCKCHIP_DRM_PLANE_FEATURE_SDR2HDR) |
4620 BIT(ROCKCHIP_DRM_PLANE_FEATURE_AFBDC));
4621 if (!vop->plane_feature_prop) {
4622 DRM_ERROR("failed to create feature property\n");
4623 return -EINVAL;
4624 }
4625
4626 plane_name_list = devm_kzalloc(vop->dev, vop->num_wins * sizeof(*plane_name_list), GFP_KERNEL);
4627 if (!plane_name_list) {
4628 DRM_DEV_ERROR(vop->dev, "failed to alloc memory for plane_name_list\n");
4629 return -ENOMEM;
4630 }
4631
4632 for (i = 0; i < vop->num_wins; i++) {
4633 struct vop_win *vop_win = &vop->win[i];
4634
4635 plane_name_list[i].type = vop_win->plane_id;
4636 plane_name_list[i].name = vop_win->name;
4637 }
4638
4639 vop->plane_name_list = plane_name_list;
4640
4641 return 0;
4642 }
4643
4644 /**
4645 * rockchip_drm_wait_vact_end
4646 * @crtc: CRTC to enable line flag
4647 * @mstimeout: millisecond for timeout
4648 *
4649 * Wait for vact_end line flag irq or timeout.
4650 *
4651 * Returns:
4652 * Zero on success, negative errno on failure.
4653 */
rockchip_drm_wait_vact_end(struct drm_crtc * crtc,unsigned int mstimeout)4654 int rockchip_drm_wait_vact_end(struct drm_crtc *crtc, unsigned int mstimeout)
4655 {
4656 struct vop *vop = to_vop(crtc);
4657 unsigned long jiffies_left;
4658 int ret = 0;
4659
4660 if (!crtc || !vop->is_enabled) {
4661 return -ENODEV;
4662 }
4663
4664 mutex_lock(&vop->vop_lock);
4665 if (mstimeout <= 0) {
4666 ret = -EINVAL;
4667 goto out;
4668 }
4669
4670 if (vop_line_flag_irq_is_enabled(vop)) {
4671 ret = -EBUSY;
4672 goto out;
4673 }
4674
4675 reinit_completion(&vop->line_flag_completion);
4676 vop_line_flag_irq_enable(vop);
4677
4678 jiffies_left = wait_for_completion_timeout(&vop->line_flag_completion, msecs_to_jiffies(mstimeout));
4679 vop_line_flag_irq_disable(vop);
4680
4681 if (jiffies_left == 0) {
4682 DRM_DEV_ERROR(vop->dev, "Timeout waiting for IRQ\n");
4683 ret = -ETIMEDOUT;
4684 goto out;
4685 }
4686
4687 out:
4688 mutex_unlock(&vop->vop_lock);
4689 return ret;
4690 }
4691 EXPORT_SYMBOL(rockchip_drm_wait_vact_end);
4692
vop_bind(struct device * dev,struct device * master,void * data)4693 static int vop_bind(struct device *dev, struct device *master, void *data)
4694 {
4695 struct platform_device *pdev = to_platform_device(dev);
4696 const struct vop_data *vop_data;
4697 struct drm_device *drm_dev = data;
4698 struct vop *vop;
4699 struct resource *res;
4700 size_t alloc_size;
4701 int ret, irq, i;
4702 int num_wins = 0;
4703 bool dual_channel_swap = false;
4704 struct device_node *mcu = NULL;
4705
4706 vop_data = of_device_get_match_data(dev);
4707 if (!vop_data) {
4708 return -ENODEV;
4709 }
4710
4711 for (i = 0; i < vop_data->win_size; i++) {
4712 const struct vop_win_data *win_data = &vop_data->win[i];
4713
4714 num_wins += win_data->area_size + 1;
4715 }
4716
4717 /* Allocate vop struct and its vop_win array */
4718 alloc_size = sizeof(*vop) + sizeof(*vop->win) * num_wins;
4719 vop = devm_kzalloc(dev, alloc_size, GFP_KERNEL);
4720 if (!vop) {
4721 return -ENOMEM;
4722 }
4723
4724 vop->dev = dev;
4725 vop->data = vop_data;
4726 vop->drm_dev = drm_dev;
4727 vop->num_wins = num_wins;
4728 vop->version = vop_data->version;
4729 vop->soc_id = vop_data->soc_id;
4730 vop->id = vop_data->vop_id;
4731 dev_set_drvdata(dev, vop);
4732 vop->support_multi_area = of_property_read_bool(dev->of_node, "support-multi-area");
4733
4734 ret = vop_win_init(vop);
4735 if (ret) {
4736 return ret;
4737 }
4738
4739 res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "regs");
4740 if (!res) {
4741 dev_warn(vop->dev, "failed to get vop register byname\n");
4742 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
4743 }
4744 vop->regs = devm_ioremap_resource(dev, res);
4745 if (IS_ERR(vop->regs)) {
4746 return PTR_ERR(vop->regs);
4747 }
4748 vop->len = resource_size(res);
4749
4750 vop->regsbak = devm_kzalloc(dev, vop->len, GFP_KERNEL);
4751 if (!vop->regsbak) {
4752 return -ENOMEM;
4753 }
4754
4755 res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "gamma_lut");
4756 if (res) {
4757 vop->lut_len = resource_size(res) / sizeof(*vop->lut);
4758 if (vop->lut_len != 0x100 && vop->lut_len != 0x400) {
4759 dev_err(vop->dev, "unsupported lut sizes %d\n", vop->lut_len);
4760 return -EINVAL;
4761 }
4762
4763 vop->lut_regs = devm_ioremap_resource(dev, res);
4764 if (IS_ERR(vop->lut_regs)) {
4765 return PTR_ERR(vop->lut_regs);
4766 }
4767 }
4768 vop->grf = syscon_regmap_lookup_by_phandle(dev->of_node, "rockchip,grf");
4769 if (IS_ERR(vop->grf)) {
4770 dev_err(dev, "missing rockchip,grf property\n");
4771 }
4772 vop->hclk = devm_clk_get(vop->dev, "hclk_vop");
4773 if (IS_ERR(vop->hclk)) {
4774 dev_err(vop->dev, "failed to get hclk source\n");
4775 return PTR_ERR(vop->hclk);
4776 }
4777 vop->aclk = devm_clk_get(vop->dev, "aclk_vop");
4778 if (IS_ERR(vop->aclk)) {
4779 dev_err(vop->dev, "failed to get aclk source\n");
4780 return PTR_ERR(vop->aclk);
4781 }
4782 vop->dclk = devm_clk_get(vop->dev, "dclk_vop");
4783 if (IS_ERR(vop->dclk)) {
4784 dev_err(vop->dev, "failed to get dclk source\n");
4785 return PTR_ERR(vop->dclk);
4786 }
4787 vop->dclk_source = devm_clk_get(vop->dev, "dclk_source");
4788 if (PTR_ERR(vop->dclk_source) == -ENOENT) {
4789 vop->dclk_source = NULL;
4790 } else if (PTR_ERR(vop->dclk_source) == -EPROBE_DEFER) {
4791 return -EPROBE_DEFER;
4792 } else if (IS_ERR(vop->dclk_source)) {
4793 dev_err(vop->dev, "failed to get dclk source parent\n");
4794 return PTR_ERR(vop->dclk_source);
4795 }
4796 irq = platform_get_irq(pdev, 0);
4797 if (irq < 0) {
4798 DRM_DEV_ERROR(dev, "cannot find irq for vop\n");
4799 return irq;
4800 }
4801 vop->irq = (unsigned int)irq;
4802
4803 spin_lock_init(&vop->reg_lock);
4804 spin_lock_init(&vop->irq_lock);
4805 mutex_init(&vop->vop_lock);
4806
4807 ret = devm_request_irq(dev, vop->irq, vop_isr, IRQF_SHARED, dev_name(dev), vop);
4808 if (ret) {
4809 return ret;
4810 }
4811 ret = vop_create_crtc(vop);
4812 if (ret) {
4813 return ret;
4814 }
4815
4816 pm_runtime_enable(&pdev->dev);
4817
4818 mcu = of_get_child_by_name(dev->of_node, "mcu-timing");
4819 if (!mcu) {
4820 dev_dbg(dev, "no mcu-timing node found in %s\n", dev->of_node->full_name);
4821 } else {
4822 u32 val;
4823
4824 if (!of_property_read_u32(mcu, "mcu-pix-total", &val)) {
4825 vop->mcu_timing.mcu_pix_total = val;
4826 }
4827 if (!of_property_read_u32(mcu, "mcu-cs-pst", &val)) {
4828 vop->mcu_timing.mcu_cs_pst = val;
4829 }
4830 if (!of_property_read_u32(mcu, "mcu-cs-pend", &val)) {
4831 vop->mcu_timing.mcu_cs_pend = val;
4832 }
4833 if (!of_property_read_u32(mcu, "mcu-rw-pst", &val)) {
4834 vop->mcu_timing.mcu_rw_pst = val;
4835 }
4836 if (!of_property_read_u32(mcu, "mcu-rw-pend", &val)) {
4837 vop->mcu_timing.mcu_rw_pend = val;
4838 }
4839 if (!of_property_read_u32(mcu, "mcu-hold-mode", &val)) {
4840 vop->mcu_timing.mcu_hold_mode = val;
4841 }
4842 }
4843
4844 dual_channel_swap = of_property_read_bool(dev->of_node, "rockchip,dual-channel-swap");
4845 vop->dual_channel_swap = dual_channel_swap;
4846
4847 return 0;
4848 }
4849
vop_unbind(struct device * dev,struct device * master,void * data)4850 static void vop_unbind(struct device *dev, struct device *master, void *data)
4851 {
4852 struct vop *vop = dev_get_drvdata(dev);
4853
4854 pm_runtime_disable(dev);
4855 vop_destroy_crtc(vop);
4856 }
4857
4858 const struct component_ops vop_component_ops = {
4859 .bind = vop_bind,
4860 .unbind = vop_unbind,
4861 };
4862 EXPORT_SYMBOL_GPL(vop_component_ops);
4863