15455Sdg// SPDX-License-Identifier: GPL-2.0
21541Srgrimes/*
31541Srgrimes * Copyright (C) STMicroelectronics SA 2014
41549Srgrimes * Authors: Benjamin Gaignard <benjamin.gaignard@st.com>
51549Srgrimes *          Fabien Dessenne <fabien.dessenne@st.com>
61549Srgrimes *          for STMicroelectronics.
71549Srgrimes */
81541Srgrimes
91549Srgrimes#include <linux/moduleparam.h>
101541Srgrimes#include <linux/seq_file.h>
111541Srgrimes
121541Srgrimes#include <drm/drm_print.h>
131541Srgrimes
141541Srgrimes#include "sti_compositor.h"
151541Srgrimes#include "sti_mixer.h"
161541Srgrimes#include "sti_vtg.h"
171541Srgrimes
181541Srgrimes/* Module parameter to set the background color of the mixer */
191541Srgrimesstatic unsigned int bkg_color = 0x000000;
201541SrgrimesMODULE_PARM_DESC(bkgcolor, "Value of the background color 0xRRGGBB");
211541Srgrimesmodule_param_named(bkgcolor, bkg_color, int, 0644);
221541Srgrimes
231541Srgrimes/* regs offset */
241541Srgrimes#define GAM_MIXER_CTL      0x00
251541Srgrimes#define GAM_MIXER_BKC      0x04
261541Srgrimes#define GAM_MIXER_BCO      0x0C
271541Srgrimes#define GAM_MIXER_BCS      0x10
281541Srgrimes#define GAM_MIXER_AVO      0x28
291541Srgrimes#define GAM_MIXER_AVS      0x2C
301541Srgrimes#define GAM_MIXER_CRB      0x34
311541Srgrimes#define GAM_MIXER_ACT      0x38
321541Srgrimes#define GAM_MIXER_MBP      0x3C
331541Srgrimes#define GAM_MIXER_MX0      0x80
341541Srgrimes
351541Srgrimes/* id for depth of CRB reg */
361541Srgrimes#define GAM_DEPTH_VID0_ID  1
371541Srgrimes#define GAM_DEPTH_VID1_ID  2
381541Srgrimes#define GAM_DEPTH_GDP0_ID  3
391541Srgrimes#define GAM_DEPTH_GDP1_ID  4
401541Srgrimes#define GAM_DEPTH_GDP2_ID  5
411817Sdg#define GAM_DEPTH_GDP3_ID  6
421541Srgrimes#define GAM_DEPTH_MASK_ID  7
431541Srgrimes
441541Srgrimes/* mask in CTL reg */
451541Srgrimes#define GAM_CTL_BACK_MASK  BIT(0)
461541Srgrimes#define GAM_CTL_VID0_MASK  BIT(1)
471541Srgrimes#define GAM_CTL_VID1_MASK  BIT(2)
485455Sdg#define GAM_CTL_GDP0_MASK  BIT(3)
491541Srgrimes#define GAM_CTL_GDP1_MASK  BIT(4)
501541Srgrimes#define GAM_CTL_GDP2_MASK  BIT(5)
511541Srgrimes#define GAM_CTL_GDP3_MASK  BIT(6)
521541Srgrimes#define GAM_CTL_CURSOR_MASK BIT(9)
531541Srgrimes
545455Sdgconst char *sti_mixer_to_str(struct sti_mixer *mixer)
555455Sdg{
565455Sdg	switch (mixer->id) {
571541Srgrimes	case STI_MIXER_MAIN:
585455Sdg		return "MAIN_MIXER";
591541Srgrimes	case STI_MIXER_AUX:
601541Srgrimes		return "AUX_MIXER";
611541Srgrimes	default:
621541Srgrimes		return "<UNKNOWN MIXER>";
631541Srgrimes	}
641541Srgrimes}
651541Srgrimes
661541Srgrimesstatic inline u32 sti_mixer_reg_read(struct sti_mixer *mixer, u32 reg_id)
671541Srgrimes{
681817Sdg	return readl(mixer->regs + reg_id);
6932286Sdyson}
701541Srgrimes
711541Srgrimesstatic inline void sti_mixer_reg_write(struct sti_mixer *mixer,
721541Srgrimes				       u32 reg_id, u32 val)
731541Srgrimes{
741541Srgrimes	writel(val, mixer->regs + reg_id);
751541Srgrimes}
761541Srgrimes
771541Srgrimes#define DBGFS_DUMP(reg) seq_printf(s, "\n  %-25s 0x%08X", #reg, \
781549Srgrimes				   sti_mixer_reg_read(mixer, reg))
799507Sdg
801549Srgrimesstatic void mixer_dbg_ctl(struct seq_file *s, int val)
8112662Sdg{
821541Srgrimes	unsigned int i;
831541Srgrimes	int count = 0;
8412662Sdg	char *const disp_layer[] = {"BKG", "VID0", "VID1", "GDP0",
8512662Sdg				    "GDP1", "GDP2", "GDP3"};
8622521Sdyson
8712662Sdg	seq_puts(s, "\tEnabled: ");
8812662Sdg	for (i = 0; i < 7; i++) {
8912662Sdg		if (val & 1) {
901541Srgrimes			seq_printf(s, "%s ", disp_layer[i]);
911541Srgrimes			count++;
924207Sdg		}
939507Sdg		val = val >> 1;
949507Sdg	}
9512662Sdg
961541Srgrimes	val = val >> 2;
9710988Sdyson	if (val & 1) {
981549Srgrimes		seq_puts(s, "CURS ");
991549Srgrimes		count++;
1001549Srgrimes	}
1011549Srgrimes	if (!count)
1021549Srgrimes		seq_puts(s, "Nothing");
1031541Srgrimes}
1041541Srgrimes
1051541Srgrimesstatic void mixer_dbg_crb(struct seq_file *s, int val)
1061541Srgrimes{
1071541Srgrimes	int i;
1081541Srgrimes
1091541Srgrimes	seq_puts(s, "\tDepth: ");
1101541Srgrimes	for (i = 0; i < GAM_MIXER_NB_DEPTH_LEVEL; i++) {
1111541Srgrimes		switch (val & GAM_DEPTH_MASK_ID) {
1121541Srgrimes		case GAM_DEPTH_VID0_ID:
1131541Srgrimes			seq_puts(s, "VID0");
1141541Srgrimes			break;
1151541Srgrimes		case GAM_DEPTH_VID1_ID:
1161541Srgrimes			seq_puts(s, "VID1");
1171541Srgrimes			break;
1181541Srgrimes		case GAM_DEPTH_GDP0_ID:
1191541Srgrimes			seq_puts(s, "GDP0");
1201541Srgrimes			break;
1211541Srgrimes		case GAM_DEPTH_GDP1_ID:
12228751Sbde			seq_puts(s, "GDP1");
1231541Srgrimes			break;
1245455Sdg		case GAM_DEPTH_GDP2_ID:
12512767Sdyson			seq_puts(s, "GDP2");
1265455Sdg			break;
1275455Sdg		case GAM_DEPTH_GDP3_ID:
12812767Sdyson			seq_puts(s, "GDP3");
1295455Sdg			break;
1305455Sdg		default:
1315455Sdg			seq_puts(s, "---");
1325455Sdg		}
1335455Sdg
1345455Sdg		if (i < GAM_MIXER_NB_DEPTH_LEVEL - 1)
1355455Sdg			seq_puts(s, " < ");
1365455Sdg		val = val >> 3;
1375455Sdg	}
1385455Sdg}
1395455Sdg
1407695Sdgstatic void mixer_dbg_mxn(struct seq_file *s, void *addr)
14122521Sdyson{
1421541Srgrimes	int i;
1435455Sdg
1441541Srgrimes	for (i = 1; i < 8; i++)
1451541Srgrimes		seq_printf(s, "-0x%08X", (int)readl(addr + i * 4));
1461541Srgrimes}
1471541Srgrimes
1481541Srgrimesstatic int mixer_dbg_show(struct seq_file *s, void *arg)
1491541Srgrimes{
1501541Srgrimes	struct drm_info_node *node = s->private;
1511541Srgrimes	struct sti_mixer *mixer = (struct sti_mixer *)node->info_ent->data;
1521541Srgrimes
1531541Srgrimes	seq_printf(s, "%s: (vaddr = 0x%p)",
15413490Sdyson		   sti_mixer_to_str(mixer), mixer->regs);
1551541Srgrimes
1561541Srgrimes	DBGFS_DUMP(GAM_MIXER_CTL);
1571541Srgrimes	mixer_dbg_ctl(s, sti_mixer_reg_read(mixer, GAM_MIXER_CTL));
1581541Srgrimes	DBGFS_DUMP(GAM_MIXER_BKC);
1591541Srgrimes	DBGFS_DUMP(GAM_MIXER_BCO);
1601541Srgrimes	DBGFS_DUMP(GAM_MIXER_BCS);
1611541Srgrimes	DBGFS_DUMP(GAM_MIXER_AVO);
1621541Srgrimes	DBGFS_DUMP(GAM_MIXER_AVS);
1631541Srgrimes	DBGFS_DUMP(GAM_MIXER_CRB);
1641541Srgrimes	mixer_dbg_crb(s, sti_mixer_reg_read(mixer, GAM_MIXER_CRB));
1656816Sdg	DBGFS_DUMP(GAM_MIXER_ACT);
1661541Srgrimes	DBGFS_DUMP(GAM_MIXER_MBP);
1671541Srgrimes	DBGFS_DUMP(GAM_MIXER_MX0);
1686816Sdg	mixer_dbg_mxn(s, mixer->regs + GAM_MIXER_MX0);
1691541Srgrimes	seq_putc(s, '\n');
1701541Srgrimes	return 0;
17122521Sdyson}
1721541Srgrimes
1731541Srgrimesstatic struct drm_info_list mixer0_debugfs_files[] = {
1741541Srgrimes	{ "mixer_main", mixer_dbg_show, 0, NULL },
1751541Srgrimes};
1761541Srgrimes
1771541Srgrimesstatic struct drm_info_list mixer1_debugfs_files[] = {
1781541Srgrimes	{ "mixer_aux", mixer_dbg_show, 0, NULL },
1791549Srgrimes};
1805455Sdg
1811541Srgrimesvoid sti_mixer_debugfs_init(struct sti_mixer *mixer, struct drm_minor *minor)
1821541Srgrimes{
1835455Sdg	unsigned int i;
1845455Sdg	struct drm_info_list *mixer_debugfs_files;
1851541Srgrimes	int nb_files;
1861541Srgrimes
18710988Sdyson	switch (mixer->id) {
18810988Sdyson	case STI_MIXER_MAIN:
18912767Sdyson		mixer_debugfs_files = mixer0_debugfs_files;
1905455Sdg		nb_files = ARRAY_SIZE(mixer0_debugfs_files);
1911541Srgrimes		break;
1927695Sdg	case STI_MIXER_AUX:
19321754Sdyson		mixer_debugfs_files = mixer1_debugfs_files;
19420054Sdyson		nb_files = ARRAY_SIZE(mixer1_debugfs_files);
19520054Sdyson		break;
19620054Sdyson	default:
19720054Sdyson		return;
19820449Sdyson	}
19920449Sdyson
20020449Sdyson	for (i = 0; i < nb_files; i++)
20120999Sdyson		mixer_debugfs_files[i].data = mixer;
20220449Sdyson
20320449Sdyson	drm_debugfs_create_files(mixer_debugfs_files,
20420449Sdyson				 nb_files,
20531853Sdyson				 minor->debugfs_root, minor);
20631853Sdyson}
20720449Sdyson
20820449Sdysonvoid sti_mixer_set_background_status(struct sti_mixer *mixer, bool enable)
20920449Sdyson{
21020449Sdyson	u32 val = sti_mixer_reg_read(mixer, GAM_MIXER_CTL);
21120449Sdyson
21220449Sdyson	val &= ~GAM_CTL_BACK_MASK;
21320449Sdyson	val |= enable;
21420449Sdyson	sti_mixer_reg_write(mixer, GAM_MIXER_CTL, val);
21520449Sdyson}
21620449Sdyson
21720449Sdysonstatic void sti_mixer_set_background_color(struct sti_mixer *mixer,
21820449Sdyson					   unsigned int rgb)
21920449Sdyson{
22020449Sdyson	sti_mixer_reg_write(mixer, GAM_MIXER_BKC, rgb);
22120449Sdyson}
22220449Sdyson
22320449Sdysonstatic void sti_mixer_set_background_area(struct sti_mixer *mixer,
22420449Sdyson					  struct drm_display_mode *mode)
22532286Sdyson{
22632286Sdyson	u32 ydo, xdo, yds, xds;
22732286Sdyson
22832286Sdyson	ydo = sti_vtg_get_line_number(*mode, 0);
22932286Sdyson	yds = sti_vtg_get_line_number(*mode, mode->vdisplay - 1);
23032286Sdyson	xdo = sti_vtg_get_pixel_number(*mode, 0);
23132286Sdyson	xds = sti_vtg_get_pixel_number(*mode, mode->hdisplay - 1);
23232286Sdyson
23332286Sdyson	sti_mixer_reg_write(mixer, GAM_MIXER_BCO, ydo << 16 | xdo);
2349507Sdg	sti_mixer_reg_write(mixer, GAM_MIXER_BCS, yds << 16 | xds);
23531853Sdyson}
23631853Sdyson
23731853Sdysonint sti_mixer_set_plane_depth(struct sti_mixer *mixer, struct sti_plane *plane)
23831853Sdyson{
2397695Sdg	int plane_id, depth = plane->drm_plane.state->normalized_zpos;
2401541Srgrimes	unsigned int i;
2411541Srgrimes	u32 mask, val;
2421541Srgrimes
2431541Srgrimes	switch (plane->desc) {
2441541Srgrimes	case STI_GDP_0:
2451541Srgrimes		plane_id = GAM_DEPTH_GDP0_ID;
2461541Srgrimes		break;
2475455Sdg	case STI_GDP_1:
2485455Sdg		plane_id = GAM_DEPTH_GDP1_ID;
2498876Srgrimes		break;
2505455Sdg	case STI_GDP_2:
2519507Sdg		plane_id = GAM_DEPTH_GDP2_ID;
2525455Sdg		break;
2538876Srgrimes	case STI_GDP_3:
2545455Sdg		plane_id = GAM_DEPTH_GDP3_ID;
2555455Sdg		break;
2568876Srgrimes	case STI_HQVDP_0:
2575455Sdg		plane_id = GAM_DEPTH_VID0_ID;
2585455Sdg		break;
2595455Sdg	case STI_CURSOR:
2605455Sdg		/* no need to set depth for cursor */
2618876Srgrimes		return 0;
2625455Sdg	default:
2635455Sdg		DRM_ERROR("Unknown plane %d\n", plane->desc);
2648876Srgrimes		return 1;
2659507Sdg	}
2665455Sdg
2675455Sdg	/* Search if a previous depth was already assigned to the plane */
2685455Sdg	val = sti_mixer_reg_read(mixer, GAM_MIXER_CRB);
2698876Srgrimes	for (i = 0; i < GAM_MIXER_NB_DEPTH_LEVEL; i++) {
2705455Sdg		mask = GAM_DEPTH_MASK_ID << (3 * i);
2715455Sdg		if ((val & mask) == plane_id << (3 * i))
2725455Sdg			break;
2731541Srgrimes	}
2741541Srgrimes
2751541Srgrimes	mask |= GAM_DEPTH_MASK_ID << (3 * depth);
2765455Sdg	plane_id = plane_id << (3 * depth);
2771541Srgrimes
2781541Srgrimes	DRM_DEBUG_DRIVER("%s %s depth=%d\n", sti_mixer_to_str(mixer),
2791541Srgrimes			 sti_plane_to_str(plane), depth);
28012767Sdyson	dev_dbg(mixer->dev, "GAM_MIXER_CRB val 0x%x mask 0x%x\n",
2811541Srgrimes		plane_id, mask);
2821541Srgrimes
2835455Sdg	val &= ~mask;
2841541Srgrimes	val |= plane_id;
2851541Srgrimes	sti_mixer_reg_write(mixer, GAM_MIXER_CRB, val);
2861541Srgrimes
28712767Sdyson	dev_dbg(mixer->dev, "Read GAM_MIXER_CRB 0x%x\n",
2881541Srgrimes		sti_mixer_reg_read(mixer, GAM_MIXER_CRB));
28916268Sdyson	return 0;
2901541Srgrimes}
2915455Sdg
2925455Sdgint sti_mixer_active_video_area(struct sti_mixer *mixer,
2931541Srgrimes				struct drm_display_mode *mode)
2945455Sdg{
2951887Sdg	u32 ydo, xdo, yds, xds;
2965455Sdg
2971541Srgrimes	ydo = sti_vtg_get_line_number(*mode, 0);
29815809Sdyson	yds = sti_vtg_get_line_number(*mode, mode->vdisplay - 1);
29915809Sdyson	xdo = sti_vtg_get_pixel_number(*mode, 0);
3005455Sdg	xds = sti_vtg_get_pixel_number(*mode, mode->hdisplay - 1);
3013612Sdg
3029507Sdg	DRM_DEBUG_DRIVER("%s active video area xdo:%d ydo:%d xds:%d yds:%d\n",
3031549Srgrimes			 sti_mixer_to_str(mixer), xdo, ydo, xds, yds);
3041887Sdg	sti_mixer_reg_write(mixer, GAM_MIXER_AVO, ydo << 16 | xdo);
3051541Srgrimes	sti_mixer_reg_write(mixer, GAM_MIXER_AVS, yds << 16 | xds);
3061541Srgrimes
3071541Srgrimes	sti_mixer_set_background_color(mixer, bkg_color);
3087695Sdg
30916268Sdyson	sti_mixer_set_background_area(mixer, mode);
31017334Sdyson	sti_mixer_set_background_status(mixer, true);
31116268Sdyson	return 0;
31210988Sdyson}
31310988Sdyson
31410988Sdysonstatic u32 sti_mixer_get_plane_mask(struct sti_plane *plane)
31518169Sdyson{
31616197Sdyson	switch (plane->desc) {
31716268Sdyson	case STI_BACK:
3185455Sdg		return GAM_CTL_BACK_MASK;
3195455Sdg	case STI_GDP_0:
3205455Sdg		return GAM_CTL_GDP0_MASK;
3215455Sdg	case STI_GDP_1:
3221541Srgrimes		return GAM_CTL_GDP1_MASK;
32316197Sdyson	case STI_GDP_2:
32415904Sdyson		return GAM_CTL_GDP2_MASK;
32525930Sdfr	case STI_GDP_3:
32617312Sdyson		return GAM_CTL_GDP3_MASK;
32713490Sdyson	case STI_HQVDP_0:
3285455Sdg		return GAM_CTL_VID0_MASK;
3295455Sdg	case STI_CURSOR:
3301541Srgrimes		return GAM_CTL_CURSOR_MASK;
3311541Srgrimes	default:
33224666Sdyson		return 0;
3331541Srgrimes	}
3341541Srgrimes}
33512767Sdyson
3368585Sdgint sti_mixer_set_plane_status(struct sti_mixer *mixer,
3378585Sdg			       struct sti_plane *plane, bool status)
3388585Sdg{
33910988Sdyson	u32 mask, val;
3401541Srgrimes
3415455Sdg	DRM_DEBUG_DRIVER("%s %s %s\n", status ? "enable" : "disable",
3421541Srgrimes			 sti_mixer_to_str(mixer), sti_plane_to_str(plane));
34312767Sdyson
34415809Sdyson	mask = sti_mixer_get_plane_mask(plane);
3451541Srgrimes	if (!mask) {
3461541Srgrimes		DRM_ERROR("Can't find layer mask\n");
3471541Srgrimes		return -EINVAL;
3481541Srgrimes	}
3491541Srgrimes
3501541Srgrimes	val = sti_mixer_reg_read(mixer, GAM_MIXER_CTL);
3511541Srgrimes	val &= ~mask;
3525455Sdg	val |= status ? mask : 0;
35324666Sdyson	sti_mixer_reg_write(mixer, GAM_MIXER_CTL, val);
3541541Srgrimes
3551549Srgrimes	return 0;
3561549Srgrimes}
35715819Sdyson
3581541Srgrimesstruct sti_mixer *sti_mixer_create(struct device *dev,
35915819Sdyson				   struct drm_device *drm_dev,
36015819Sdyson				   int id,
36115819Sdyson				   void __iomem *baseaddr)
36215819Sdyson{
36315819Sdyson	struct sti_mixer *mixer = devm_kzalloc(dev, sizeof(*mixer), GFP_KERNEL);
36415819Sdyson
36515819Sdyson	dev_dbg(dev, "%s\n", __func__);
36616058Sdyson	if (!mixer) {
36716058Sdyson		DRM_ERROR("Failed to allocated memory for mixer\n");
36815819Sdyson		return NULL;
36915819Sdyson	}
37015819Sdyson	mixer->regs = baseaddr;
37115819Sdyson	mixer->dev = dev;
37215819Sdyson	mixer->id = id;
37315819Sdyson
37415819Sdyson	DRM_DEBUG_DRIVER("%s created. Regs=%p\n",
37515819Sdyson			 sti_mixer_to_str(mixer), mixer->regs);
37615819Sdyson
37724678Speter	return mixer;
37815819Sdyson}
37915819Sdyson