18097Sjkh// SPDX-License-Identifier: GPL-2.0
28097Sjkh/*
38097Sjkh * Copyright (C) STMicroelectronics SA 2014
48097Sjkh * Author: Fabien Dessenne <fabien.dessenne@st.com> for STMicroelectronics.
58097Sjkh */
68097Sjkh#include <linux/seq_file.h>
750479Speter
88097Sjkh#include <drm/drm_debugfs.h>
98097Sjkh#include <drm/drm_file.h>
108097Sjkh#include <drm/drm_print.h>
118097Sjkh
128097Sjkh#include "sti_plane.h"
138097Sjkh#include "sti_vid.h"
148097Sjkh#include "sti_vtg.h"
158097Sjkh
168881Srgrimes/* Registers */
178881Srgrimes#define VID_CTL                 0x00
188097Sjkh#define VID_ALP                 0x04
198097Sjkh#define VID_CLF                 0x08
208097Sjkh#define VID_VPO                 0x0C
218097Sjkh#define VID_VPS                 0x10
228097Sjkh#define VID_KEY1                0x28
238097Sjkh#define VID_KEY2                0x2C
248097Sjkh#define VID_MPR0                0x30
258097Sjkh#define VID_MPR1                0x34
268097Sjkh#define VID_MPR2                0x38
278097Sjkh#define VID_MPR3                0x3C
288097Sjkh#define VID_MST                 0x68
298097Sjkh#define VID_BC                  0x70
308097Sjkh#define VID_TINT                0x74
318097Sjkh#define VID_CSAT                0x78
328097Sjkh
338097Sjkh/* Registers values */
348097Sjkh#define VID_CTL_IGNORE          (BIT(31) | BIT(30))
358097Sjkh#define VID_CTL_PSI_ENABLE      (BIT(2) | BIT(1) | BIT(0))
368097Sjkh#define VID_ALP_OPAQUE          0x00000080
378097Sjkh#define VID_BC_DFLT             0x00008000
388097Sjkh#define VID_TINT_DFLT           0x00000000
398097Sjkh#define VID_CSAT_DFLT           0x00000080
4021243Sjkh/* YCbCr to RGB BT709:
4121243Sjkh * R = Y+1.5391Cr
4237735Sjkh * G = Y-0.4590Cr-0.1826Cb
4325052Sjkh * B = Y+1.8125Cb */
448097Sjkh#define VID_MPR0_BT709          0x0A800000
458097Sjkh#define VID_MPR1_BT709          0x0AC50000
468097Sjkh#define VID_MPR2_BT709          0x07150545
478097Sjkh#define VID_MPR3_BT709          0x00000AE8
488097Sjkh/* YCbCr to RGB BT709:
4921243Sjkh * R = Y+1.3711Cr
5021243Sjkh * G = Y-0.6992Cr-0.3359Cb
5121243Sjkh * B = Y+1.7344Cb
528281Sjkh */
538405Sjkh#define VID_MPR0_BT601          0x0A800000
548097Sjkh#define VID_MPR1_BT601          0x0AAF0000
558208Sjkh#define VID_MPR2_BT601          0x094E0754
568208Sjkh#define VID_MPR3_BT601          0x00000ADD
5793401Smurray
5893401Smurray#define VID_MIN_HD_HEIGHT       720
5993401Smurray
608208Sjkh#define DBGFS_DUMP(reg) seq_printf(s, "\n  %-25s 0x%08X", #reg, \
6112661Speter				   readl(vid->regs + reg))
6212661Speter
638549Sjkhstatic void vid_dbg_ctl(struct seq_file *s, int val)
6417007Sjkh{
658208Sjkh	val = val >> 30;
6621806Sjkh	seq_putc(s, '\t');
6721806Sjkh
6821806Sjkh	if (!(val & 1))
698705Sjkh		seq_puts(s, "NOT ");
708705Sjkh	seq_puts(s, "ignored on main mixer - ");
718705Sjkh
728705Sjkh	if (!(val & 2))
738705Sjkh		seq_puts(s, "NOT ");
748705Sjkh	seq_puts(s, "ignored on aux mixer");
758705Sjkh}
768705Sjkh
7712661Speterstatic void vid_dbg_vpo(struct seq_file *s, int val)
788208Sjkh{
7912661Speter	seq_printf(s, "\txdo:%4d\tydo:%4d", val & 0x0FFF, (val >> 16) & 0x0FFF);
8015788Sjkh}
8115788Sjkh
8215788Sjkhstatic void vid_dbg_vps(struct seq_file *s, int val)
8315788Sjkh{
8415788Sjkh	seq_printf(s, "\txds:%4d\tyds:%4d", val & 0x0FFF, (val >> 16) & 0x0FFF);
8515788Sjkh}
868549Sjkh
8712661Speterstatic void vid_dbg_mst(struct seq_file *s, int val)
8812661Speter{
8912661Speter	if (val & 1)
9012661Speter		seq_puts(s, "\tBUFFER UNDERFLOW!");
9112661Speter}
9212661Speter
9312661Speterstatic int vid_dbg_show(struct seq_file *s, void *arg)
9446117Sjkh{
9512661Speter	struct drm_info_node *node = s->private;
9626456Sjkh	struct sti_vid *vid = (struct sti_vid *)node->info_ent->data;
9725473Spst
9857613Sjkh	seq_printf(s, "VID: (vaddr= 0x%p)", vid->regs);
9925473Spst
10025473Spst	DBGFS_DUMP(VID_CTL);
10125473Spst	vid_dbg_ctl(s, readl(vid->regs + VID_CTL));
10225473Spst	DBGFS_DUMP(VID_ALP);
10325473Spst	DBGFS_DUMP(VID_CLF);
10412661Speter	DBGFS_DUMP(VID_VPO);
10514763Sjkh	vid_dbg_vpo(s, readl(vid->regs + VID_VPO));
10612661Speter	DBGFS_DUMP(VID_VPS);
10729539Spst	vid_dbg_vps(s, readl(vid->regs + VID_VPS));
10829539Spst	DBGFS_DUMP(VID_KEY1);
10960657Sobrien	DBGFS_DUMP(VID_KEY2);
11016410Sjkh	DBGFS_DUMP(VID_MPR0);
11112661Speter	DBGFS_DUMP(VID_MPR1);
11243688Sjkh	DBGFS_DUMP(VID_MPR2);
11316462Sjkh	DBGFS_DUMP(VID_MPR3);
11412661Speter	DBGFS_DUMP(VID_MST);
11512661Speter	vid_dbg_mst(s, readl(vid->regs + VID_MST));
11616410Sjkh	DBGFS_DUMP(VID_BC);
11755392Sjkh	DBGFS_DUMP(VID_TINT);
11866369Sjkh	DBGFS_DUMP(VID_CSAT);
11955392Sjkh	seq_putc(s, '\n');
12055392Sjkh	return 0;
12155392Sjkh}
12212661Speter
12312661Speterstatic struct drm_info_list vid_debugfs_files[] = {
12412661Speter	{ "vid", vid_dbg_show, 0, NULL },
12512661Speter};
12624038Sjkh
12717034Sjkhvoid vid_debugfs_init(struct sti_vid *vid, struct drm_minor *minor)
12812661Speter{
12963118Sume	unsigned int i;
13063118Sume
13129539Spst	for (i = 0; i < ARRAY_SIZE(vid_debugfs_files); i++)
13212661Speter		vid_debugfs_files[i].data = vid;
13312661Speter
13448624Sjkh	drm_debugfs_create_files(vid_debugfs_files,
13512661Speter				 ARRAY_SIZE(vid_debugfs_files),
13621855Sjkh				 minor->debugfs_root, minor);
13734150Sjkh}
13859088Smurray
13934150Sjkhvoid sti_vid_commit(struct sti_vid *vid,
14034150Sjkh		    struct drm_plane_state *state)
14112661Speter{
14229539Spst	struct drm_crtc *crtc = state->crtc;
14312661Speter	struct drm_display_mode *mode = &crtc->mode;
14426514Sjkh	int dst_x = state->crtc_x;
14549441Sphk	int dst_y = state->crtc_y;
14612661Speter	int dst_w = clamp_val(state->crtc_w, 0, mode->hdisplay - dst_x);
14716410Sjkh	int dst_h = clamp_val(state->crtc_h, 0, mode->vdisplay - dst_y);
14843685Sjkh	int src_h = state->src_h >> 16;
14926010Sjkh	u32 val, ydo, xdo, yds, xds;
15012661Speter
15126795Sjkh	/* Input / output size
15274177Sjkh	 * Align to upper even value */
15326717Sjkh	dst_w = ALIGN(dst_w, 2);
15437735Sjkh	dst_h = ALIGN(dst_h, 2);
15587583Sdillon
15687557Sdillon	/* Unmask */
15726456Sjkh	val = readl(vid->regs + VID_CTL);
15816828Sjkh	val &= ~VID_CTL_IGNORE;
15929539Spst	writel(val, vid->regs + VID_CTL);
16029539Spst
16126456Sjkh	ydo = sti_vtg_get_line_number(*mode, dst_y);
16216366Sjkh	yds = sti_vtg_get_line_number(*mode, dst_y + dst_h - 1);
16316366Sjkh	xdo = sti_vtg_get_pixel_number(*mode, dst_x);
16412661Speter	xds = sti_vtg_get_pixel_number(*mode, dst_x + dst_w - 1);
16549110Sbrian
16649110Sbrian	writel((ydo << 16) | xdo, vid->regs + VID_VPO);
16712661Speter	writel((yds << 16) | xds, vid->regs + VID_VPS);
16812661Speter
16919385Sjkh	/* Color conversion parameters */
17025476Sjkh	if (src_h >= VID_MIN_HD_HEIGHT) {
17150797Sjkh		writel(VID_MPR0_BT709, vid->regs + VID_MPR0);
17216366Sjkh		writel(VID_MPR1_BT709, vid->regs + VID_MPR1);
17312661Speter		writel(VID_MPR2_BT709, vid->regs + VID_MPR2);
17412661Speter		writel(VID_MPR3_BT709, vid->regs + VID_MPR3);
17512661Speter	} else {
17650780Sjkh		writel(VID_MPR0_BT601, vid->regs + VID_MPR0);
17763118Sume		writel(VID_MPR1_BT601, vid->regs + VID_MPR1);
17812661Speter		writel(VID_MPR2_BT601, vid->regs + VID_MPR2);
17912661Speter		writel(VID_MPR3_BT601, vid->regs + VID_MPR3);
18012661Speter	}
18187583Sdillon}
18287557Sdillon
18343688Sjkhvoid sti_vid_disable(struct sti_vid *vid)
18478160Solgeni{
18579813Sache	u32 val;
1869202Srgrimes
18712661Speter	/* Mask */
1889202Srgrimes	val = readl(vid->regs + VID_CTL);
18912661Speter	val |= VID_CTL_IGNORE;
19012661Speter	writel(val, vid->regs + VID_CTL);
19157617Sjkh}
1928549Sjkh
19316208Sjkhstatic void sti_vid_init(struct sti_vid *vid)
19416294Sjkh{
19516366Sjkh	/* Enable PSI, Mask layer */
19616208Sjkh	writel(VID_CTL_PSI_ENABLE | VID_CTL_IGNORE, vid->regs + VID_CTL);
19720247Sjkh
19820569Sjkh	/* Opaque */
19916366Sjkh	writel(VID_ALP_OPAQUE, vid->regs + VID_ALP);
2008208Sjkh
20176402Sjkh	/* Brightness, contrast, tint, saturation */
2028549Sjkh	writel(VID_BC_DFLT, vid->regs + VID_BC);
2038549Sjkh	writel(VID_TINT_DFLT, vid->regs + VID_TINT);
2048097Sjkh	writel(VID_CSAT_DFLT, vid->regs + VID_CSAT);
20515242Sjkh}
20615242Sjkh
20715242Sjkhstruct sti_vid *sti_vid_create(struct device *dev, struct drm_device *drm_dev,
20815242Sjkh			       int id, void __iomem *baseaddr)
20915242Sjkh{
2108097Sjkh	struct sti_vid *vid;
2118097Sjkh
21215242Sjkh	vid = devm_kzalloc(dev, sizeof(*vid), GFP_KERNEL);
2138174Sjkh	if (!vid) {
2148174Sjkh		DRM_ERROR("Failed to allocate memory for VID\n");
2158174Sjkh		return NULL;
2168174Sjkh	}
21794056Smurray
21894056Smurray	vid->dev = dev;
21994056Smurray	vid->regs = baseaddr;
22015091Sjkh	vid->id = id;
22194056Smurray
22294056Smurray	sti_vid_init(vid);
22394056Smurray
2248097Sjkh	return vid;
2258097Sjkh}
22625251Sjkh