xref: /openbmc/linux/drivers/gpu/drm/sti/sti_vid.c (revision 54ac836b)
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)12754ac836bSWambui 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 
13454ac836bSWambui 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