1e2842570SBenjamin Gaignard // SPDX-License-Identifier: GPL-2.0
2cfd8d744SBenjamin Gaignard /*
3cfd8d744SBenjamin Gaignard * Copyright (C) STMicroelectronics SA 2014
4cfd8d744SBenjamin Gaignard * Author: Fabien Dessenne <fabien.dessenne@st.com> for STMicroelectronics.
5cfd8d744SBenjamin Gaignard */
60f3e1561SArnd Bergmann #include <linux/seq_file.h>
7cfd8d744SBenjamin Gaignard
85e2f97a9SSam Ravnborg #include <drm/drm_debugfs.h>
95e2f97a9SSam Ravnborg #include <drm/drm_file.h>
105e2f97a9SSam Ravnborg #include <drm/drm_print.h>
11cfd8d744SBenjamin Gaignard
129e1f05b2SVincent Abriou #include "sti_plane.h"
13cfd8d744SBenjamin Gaignard #include "sti_vid.h"
14cfd8d744SBenjamin Gaignard #include "sti_vtg.h"
15cfd8d744SBenjamin Gaignard
16cfd8d744SBenjamin Gaignard /* Registers */
17cfd8d744SBenjamin Gaignard #define VID_CTL 0x00
18cfd8d744SBenjamin Gaignard #define VID_ALP 0x04
19cfd8d744SBenjamin Gaignard #define VID_CLF 0x08
20cfd8d744SBenjamin Gaignard #define VID_VPO 0x0C
21cfd8d744SBenjamin Gaignard #define VID_VPS 0x10
22cfd8d744SBenjamin Gaignard #define VID_KEY1 0x28
23cfd8d744SBenjamin Gaignard #define VID_KEY2 0x2C
24cfd8d744SBenjamin Gaignard #define VID_MPR0 0x30
25cfd8d744SBenjamin Gaignard #define VID_MPR1 0x34
26cfd8d744SBenjamin Gaignard #define VID_MPR2 0x38
27cfd8d744SBenjamin Gaignard #define VID_MPR3 0x3C
28cfd8d744SBenjamin Gaignard #define VID_MST 0x68
29cfd8d744SBenjamin Gaignard #define VID_BC 0x70
30cfd8d744SBenjamin Gaignard #define VID_TINT 0x74
31cfd8d744SBenjamin Gaignard #define VID_CSAT 0x78
32cfd8d744SBenjamin Gaignard
33cfd8d744SBenjamin Gaignard /* Registers values */
34cfd8d744SBenjamin Gaignard #define VID_CTL_IGNORE (BIT(31) | BIT(30))
35cfd8d744SBenjamin Gaignard #define VID_CTL_PSI_ENABLE (BIT(2) | BIT(1) | BIT(0))
36cfd8d744SBenjamin Gaignard #define VID_ALP_OPAQUE 0x00000080
37cfd8d744SBenjamin Gaignard #define VID_BC_DFLT 0x00008000
38cfd8d744SBenjamin Gaignard #define VID_TINT_DFLT 0x00000000
39cfd8d744SBenjamin Gaignard #define VID_CSAT_DFLT 0x00000080
40cfd8d744SBenjamin Gaignard /* YCbCr to RGB BT709:
41cfd8d744SBenjamin Gaignard * R = Y+1.5391Cr
42cfd8d744SBenjamin Gaignard * G = Y-0.4590Cr-0.1826Cb
43cfd8d744SBenjamin Gaignard * B = Y+1.8125Cb */
44cfd8d744SBenjamin Gaignard #define VID_MPR0_BT709 0x0A800000
45cfd8d744SBenjamin Gaignard #define VID_MPR1_BT709 0x0AC50000
46cfd8d744SBenjamin Gaignard #define VID_MPR2_BT709 0x07150545
47cfd8d744SBenjamin Gaignard #define VID_MPR3_BT709 0x00000AE8
4805a142c2SBich Hemon /* YCbCr to RGB BT709:
4905a142c2SBich Hemon * R = Y+1.3711Cr
5005a142c2SBich Hemon * G = Y-0.6992Cr-0.3359Cb
5105a142c2SBich Hemon * B = Y+1.7344Cb
5205a142c2SBich Hemon */
5305a142c2SBich Hemon #define VID_MPR0_BT601 0x0A800000
5405a142c2SBich Hemon #define VID_MPR1_BT601 0x0AAF0000
5505a142c2SBich Hemon #define VID_MPR2_BT601 0x094E0754
5605a142c2SBich Hemon #define VID_MPR3_BT601 0x00000ADD
5705a142c2SBich Hemon
5805a142c2SBich Hemon #define VID_MIN_HD_HEIGHT 720
59cfd8d744SBenjamin Gaignard
6090dffef5SVincent Abriou #define DBGFS_DUMP(reg) seq_printf(s, "\n %-25s 0x%08X", #reg, \
6190dffef5SVincent Abriou readl(vid->regs + reg))
6290dffef5SVincent Abriou
vid_dbg_ctl(struct seq_file * s,int val)6390dffef5SVincent Abriou static void vid_dbg_ctl(struct seq_file *s, int val)
6490dffef5SVincent Abriou {
6590dffef5SVincent Abriou val = val >> 30;
66e9635133SMarkus Elfring seq_putc(s, '\t');
6790dffef5SVincent Abriou
6890dffef5SVincent Abriou if (!(val & 1))
6990dffef5SVincent Abriou seq_puts(s, "NOT ");
7090dffef5SVincent Abriou seq_puts(s, "ignored on main mixer - ");
7190dffef5SVincent Abriou
7290dffef5SVincent Abriou if (!(val & 2))
7390dffef5SVincent Abriou seq_puts(s, "NOT ");
7490dffef5SVincent Abriou seq_puts(s, "ignored on aux mixer");
7590dffef5SVincent Abriou }
7690dffef5SVincent Abriou
vid_dbg_vpo(struct seq_file * s,int val)7790dffef5SVincent Abriou static void vid_dbg_vpo(struct seq_file *s, int val)
7890dffef5SVincent Abriou {
7990dffef5SVincent Abriou seq_printf(s, "\txdo:%4d\tydo:%4d", val & 0x0FFF, (val >> 16) & 0x0FFF);
8090dffef5SVincent Abriou }
8190dffef5SVincent Abriou
vid_dbg_vps(struct seq_file * s,int val)8290dffef5SVincent Abriou static void vid_dbg_vps(struct seq_file *s, int val)
8390dffef5SVincent Abriou {
8490dffef5SVincent Abriou seq_printf(s, "\txds:%4d\tyds:%4d", val & 0x0FFF, (val >> 16) & 0x0FFF);
8590dffef5SVincent Abriou }
8690dffef5SVincent Abriou
vid_dbg_mst(struct seq_file * s,int val)8790dffef5SVincent Abriou static void vid_dbg_mst(struct seq_file *s, int val)
8890dffef5SVincent Abriou {
8990dffef5SVincent Abriou if (val & 1)
9090dffef5SVincent Abriou seq_puts(s, "\tBUFFER UNDERFLOW!");
9190dffef5SVincent Abriou }
9290dffef5SVincent Abriou
vid_dbg_show(struct seq_file * s,void * arg)9390dffef5SVincent Abriou static int vid_dbg_show(struct seq_file *s, void *arg)
9490dffef5SVincent Abriou {
9590dffef5SVincent Abriou struct drm_info_node *node = s->private;
9690dffef5SVincent Abriou struct sti_vid *vid = (struct sti_vid *)node->info_ent->data;
9790dffef5SVincent Abriou
9890dffef5SVincent Abriou seq_printf(s, "VID: (vaddr= 0x%p)", vid->regs);
9990dffef5SVincent Abriou
10090dffef5SVincent Abriou DBGFS_DUMP(VID_CTL);
10190dffef5SVincent Abriou vid_dbg_ctl(s, readl(vid->regs + VID_CTL));
10290dffef5SVincent Abriou DBGFS_DUMP(VID_ALP);
10390dffef5SVincent Abriou DBGFS_DUMP(VID_CLF);
10490dffef5SVincent Abriou DBGFS_DUMP(VID_VPO);
10590dffef5SVincent Abriou vid_dbg_vpo(s, readl(vid->regs + VID_VPO));
10690dffef5SVincent Abriou DBGFS_DUMP(VID_VPS);
10790dffef5SVincent Abriou vid_dbg_vps(s, readl(vid->regs + VID_VPS));
10890dffef5SVincent Abriou DBGFS_DUMP(VID_KEY1);
10990dffef5SVincent Abriou DBGFS_DUMP(VID_KEY2);
11090dffef5SVincent Abriou DBGFS_DUMP(VID_MPR0);
11190dffef5SVincent Abriou DBGFS_DUMP(VID_MPR1);
11290dffef5SVincent Abriou DBGFS_DUMP(VID_MPR2);
11390dffef5SVincent Abriou DBGFS_DUMP(VID_MPR3);
11490dffef5SVincent Abriou DBGFS_DUMP(VID_MST);
11590dffef5SVincent Abriou vid_dbg_mst(s, readl(vid->regs + VID_MST));
11690dffef5SVincent Abriou DBGFS_DUMP(VID_BC);
11790dffef5SVincent Abriou DBGFS_DUMP(VID_TINT);
11890dffef5SVincent Abriou DBGFS_DUMP(VID_CSAT);
119e9635133SMarkus Elfring seq_putc(s, '\n');
12090dffef5SVincent Abriou return 0;
12190dffef5SVincent Abriou }
12290dffef5SVincent Abriou
12390dffef5SVincent Abriou static struct drm_info_list vid_debugfs_files[] = {
12490dffef5SVincent Abriou { "vid", vid_dbg_show, 0, NULL },
12590dffef5SVincent Abriou };
12690dffef5SVincent Abriou
vid_debugfs_init(struct sti_vid * vid,struct drm_minor * minor)127*54ac836bSWambui Karuga void vid_debugfs_init(struct sti_vid *vid, struct drm_minor *minor)
12890dffef5SVincent Abriou {
12990dffef5SVincent Abriou unsigned int i;
13090dffef5SVincent Abriou
13190dffef5SVincent Abriou for (i = 0; i < ARRAY_SIZE(vid_debugfs_files); i++)
13290dffef5SVincent Abriou vid_debugfs_files[i].data = vid;
13390dffef5SVincent Abriou
134*54ac836bSWambui Karuga drm_debugfs_create_files(vid_debugfs_files,
13590dffef5SVincent Abriou ARRAY_SIZE(vid_debugfs_files),
13690dffef5SVincent Abriou minor->debugfs_root, minor);
13790dffef5SVincent Abriou }
13890dffef5SVincent Abriou
sti_vid_commit(struct sti_vid * vid,struct drm_plane_state * state)13929d1dc62SVincent Abriou void sti_vid_commit(struct sti_vid *vid,
14029d1dc62SVincent Abriou struct drm_plane_state *state)
141cfd8d744SBenjamin Gaignard {
14229d1dc62SVincent Abriou struct drm_crtc *crtc = state->crtc;
14329d1dc62SVincent Abriou struct drm_display_mode *mode = &crtc->mode;
14429d1dc62SVincent Abriou int dst_x = state->crtc_x;
14529d1dc62SVincent Abriou int dst_y = state->crtc_y;
146f766c6c8SFabien Dessenne int dst_w = clamp_val(state->crtc_w, 0, mode->hdisplay - dst_x);
147f766c6c8SFabien Dessenne int dst_h = clamp_val(state->crtc_h, 0, mode->vdisplay - dst_y);
14805a142c2SBich Hemon int src_h = state->src_h >> 16;
149871bcdfeSVincent Abriou u32 val, ydo, xdo, yds, xds;
150cfd8d744SBenjamin Gaignard
15129d1dc62SVincent Abriou /* Input / output size
15229d1dc62SVincent Abriou * Align to upper even value */
15329d1dc62SVincent Abriou dst_w = ALIGN(dst_w, 2);
15429d1dc62SVincent Abriou dst_h = ALIGN(dst_h, 2);
15529d1dc62SVincent Abriou
156cfd8d744SBenjamin Gaignard /* Unmask */
157cfd8d744SBenjamin Gaignard val = readl(vid->regs + VID_CTL);
158cfd8d744SBenjamin Gaignard val &= ~VID_CTL_IGNORE;
159cfd8d744SBenjamin Gaignard writel(val, vid->regs + VID_CTL);
160cfd8d744SBenjamin Gaignard
16129d1dc62SVincent Abriou ydo = sti_vtg_get_line_number(*mode, dst_y);
16229d1dc62SVincent Abriou yds = sti_vtg_get_line_number(*mode, dst_y + dst_h - 1);
16329d1dc62SVincent Abriou xdo = sti_vtg_get_pixel_number(*mode, dst_x);
16429d1dc62SVincent Abriou xds = sti_vtg_get_pixel_number(*mode, dst_x + dst_w - 1);
165cfd8d744SBenjamin Gaignard
166cfd8d744SBenjamin Gaignard writel((ydo << 16) | xdo, vid->regs + VID_VPO);
167cfd8d744SBenjamin Gaignard writel((yds << 16) | xds, vid->regs + VID_VPS);
16805a142c2SBich Hemon
16905a142c2SBich Hemon /* Color conversion parameters */
17005a142c2SBich Hemon if (src_h >= VID_MIN_HD_HEIGHT) {
17105a142c2SBich Hemon writel(VID_MPR0_BT709, vid->regs + VID_MPR0);
17205a142c2SBich Hemon writel(VID_MPR1_BT709, vid->regs + VID_MPR1);
17305a142c2SBich Hemon writel(VID_MPR2_BT709, vid->regs + VID_MPR2);
17405a142c2SBich Hemon writel(VID_MPR3_BT709, vid->regs + VID_MPR3);
17505a142c2SBich Hemon } else {
17605a142c2SBich Hemon writel(VID_MPR0_BT601, vid->regs + VID_MPR0);
17705a142c2SBich Hemon writel(VID_MPR1_BT601, vid->regs + VID_MPR1);
17805a142c2SBich Hemon writel(VID_MPR2_BT601, vid->regs + VID_MPR2);
17905a142c2SBich Hemon writel(VID_MPR3_BT601, vid->regs + VID_MPR3);
18005a142c2SBich Hemon }
181cfd8d744SBenjamin Gaignard }
182cfd8d744SBenjamin Gaignard
sti_vid_disable(struct sti_vid * vid)18329d1dc62SVincent Abriou void sti_vid_disable(struct sti_vid *vid)
184cfd8d744SBenjamin Gaignard {
185cfd8d744SBenjamin Gaignard u32 val;
186cfd8d744SBenjamin Gaignard
187cfd8d744SBenjamin Gaignard /* Mask */
188cfd8d744SBenjamin Gaignard val = readl(vid->regs + VID_CTL);
189cfd8d744SBenjamin Gaignard val |= VID_CTL_IGNORE;
190cfd8d744SBenjamin Gaignard writel(val, vid->regs + VID_CTL);
191cfd8d744SBenjamin Gaignard }
192cfd8d744SBenjamin Gaignard
sti_vid_init(struct sti_vid * vid)193871bcdfeSVincent Abriou static void sti_vid_init(struct sti_vid *vid)
194cfd8d744SBenjamin Gaignard {
195cfd8d744SBenjamin Gaignard /* Enable PSI, Mask layer */
196cfd8d744SBenjamin Gaignard writel(VID_CTL_PSI_ENABLE | VID_CTL_IGNORE, vid->regs + VID_CTL);
197cfd8d744SBenjamin Gaignard
198cfd8d744SBenjamin Gaignard /* Opaque */
199cfd8d744SBenjamin Gaignard writel(VID_ALP_OPAQUE, vid->regs + VID_ALP);
200cfd8d744SBenjamin Gaignard
201cfd8d744SBenjamin Gaignard /* Brightness, contrast, tint, saturation */
202cfd8d744SBenjamin Gaignard writel(VID_BC_DFLT, vid->regs + VID_BC);
203cfd8d744SBenjamin Gaignard writel(VID_TINT_DFLT, vid->regs + VID_TINT);
204cfd8d744SBenjamin Gaignard writel(VID_CSAT_DFLT, vid->regs + VID_CSAT);
205cfd8d744SBenjamin Gaignard }
206cfd8d744SBenjamin Gaignard
sti_vid_create(struct device * dev,struct drm_device * drm_dev,int id,void __iomem * baseaddr)20790dffef5SVincent Abriou struct sti_vid *sti_vid_create(struct device *dev, struct drm_device *drm_dev,
20890dffef5SVincent Abriou int id, void __iomem *baseaddr)
209cfd8d744SBenjamin Gaignard {
210871bcdfeSVincent Abriou struct sti_vid *vid;
211cfd8d744SBenjamin Gaignard
212cfd8d744SBenjamin Gaignard vid = devm_kzalloc(dev, sizeof(*vid), GFP_KERNEL);
213cfd8d744SBenjamin Gaignard if (!vid) {
214cfd8d744SBenjamin Gaignard DRM_ERROR("Failed to allocate memory for VID\n");
215cfd8d744SBenjamin Gaignard return NULL;
216cfd8d744SBenjamin Gaignard }
217cfd8d744SBenjamin Gaignard
218871bcdfeSVincent Abriou vid->dev = dev;
219871bcdfeSVincent Abriou vid->regs = baseaddr;
220871bcdfeSVincent Abriou vid->id = id;
221871bcdfeSVincent Abriou
222871bcdfeSVincent Abriou sti_vid_init(vid);
223cfd8d744SBenjamin Gaignard
224cfd8d744SBenjamin Gaignard return vid;
225cfd8d744SBenjamin Gaignard }
226