18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * Copyright (C) STMicroelectronics SA 2014
48c2ecf20Sopenharmony_ci * Authors: Benjamin Gaignard <benjamin.gaignard@st.com>
58c2ecf20Sopenharmony_ci *          Fabien Dessenne <fabien.dessenne@st.com>
68c2ecf20Sopenharmony_ci *          for STMicroelectronics.
78c2ecf20Sopenharmony_ci */
88c2ecf20Sopenharmony_ci
98c2ecf20Sopenharmony_ci#include <linux/moduleparam.h>
108c2ecf20Sopenharmony_ci#include <linux/seq_file.h>
118c2ecf20Sopenharmony_ci
128c2ecf20Sopenharmony_ci#include <drm/drm_print.h>
138c2ecf20Sopenharmony_ci
148c2ecf20Sopenharmony_ci#include "sti_compositor.h"
158c2ecf20Sopenharmony_ci#include "sti_mixer.h"
168c2ecf20Sopenharmony_ci#include "sti_vtg.h"
178c2ecf20Sopenharmony_ci
188c2ecf20Sopenharmony_ci/* Module parameter to set the background color of the mixer */
198c2ecf20Sopenharmony_cistatic unsigned int bkg_color = 0x000000;
208c2ecf20Sopenharmony_ciMODULE_PARM_DESC(bkgcolor, "Value of the background color 0xRRGGBB");
218c2ecf20Sopenharmony_cimodule_param_named(bkgcolor, bkg_color, int, 0644);
228c2ecf20Sopenharmony_ci
238c2ecf20Sopenharmony_ci/* regs offset */
248c2ecf20Sopenharmony_ci#define GAM_MIXER_CTL      0x00
258c2ecf20Sopenharmony_ci#define GAM_MIXER_BKC      0x04
268c2ecf20Sopenharmony_ci#define GAM_MIXER_BCO      0x0C
278c2ecf20Sopenharmony_ci#define GAM_MIXER_BCS      0x10
288c2ecf20Sopenharmony_ci#define GAM_MIXER_AVO      0x28
298c2ecf20Sopenharmony_ci#define GAM_MIXER_AVS      0x2C
308c2ecf20Sopenharmony_ci#define GAM_MIXER_CRB      0x34
318c2ecf20Sopenharmony_ci#define GAM_MIXER_ACT      0x38
328c2ecf20Sopenharmony_ci#define GAM_MIXER_MBP      0x3C
338c2ecf20Sopenharmony_ci#define GAM_MIXER_MX0      0x80
348c2ecf20Sopenharmony_ci
358c2ecf20Sopenharmony_ci/* id for depth of CRB reg */
368c2ecf20Sopenharmony_ci#define GAM_DEPTH_VID0_ID  1
378c2ecf20Sopenharmony_ci#define GAM_DEPTH_VID1_ID  2
388c2ecf20Sopenharmony_ci#define GAM_DEPTH_GDP0_ID  3
398c2ecf20Sopenharmony_ci#define GAM_DEPTH_GDP1_ID  4
408c2ecf20Sopenharmony_ci#define GAM_DEPTH_GDP2_ID  5
418c2ecf20Sopenharmony_ci#define GAM_DEPTH_GDP3_ID  6
428c2ecf20Sopenharmony_ci#define GAM_DEPTH_MASK_ID  7
438c2ecf20Sopenharmony_ci
448c2ecf20Sopenharmony_ci/* mask in CTL reg */
458c2ecf20Sopenharmony_ci#define GAM_CTL_BACK_MASK  BIT(0)
468c2ecf20Sopenharmony_ci#define GAM_CTL_VID0_MASK  BIT(1)
478c2ecf20Sopenharmony_ci#define GAM_CTL_VID1_MASK  BIT(2)
488c2ecf20Sopenharmony_ci#define GAM_CTL_GDP0_MASK  BIT(3)
498c2ecf20Sopenharmony_ci#define GAM_CTL_GDP1_MASK  BIT(4)
508c2ecf20Sopenharmony_ci#define GAM_CTL_GDP2_MASK  BIT(5)
518c2ecf20Sopenharmony_ci#define GAM_CTL_GDP3_MASK  BIT(6)
528c2ecf20Sopenharmony_ci#define GAM_CTL_CURSOR_MASK BIT(9)
538c2ecf20Sopenharmony_ci
548c2ecf20Sopenharmony_ciconst char *sti_mixer_to_str(struct sti_mixer *mixer)
558c2ecf20Sopenharmony_ci{
568c2ecf20Sopenharmony_ci	switch (mixer->id) {
578c2ecf20Sopenharmony_ci	case STI_MIXER_MAIN:
588c2ecf20Sopenharmony_ci		return "MAIN_MIXER";
598c2ecf20Sopenharmony_ci	case STI_MIXER_AUX:
608c2ecf20Sopenharmony_ci		return "AUX_MIXER";
618c2ecf20Sopenharmony_ci	default:
628c2ecf20Sopenharmony_ci		return "<UNKNOWN MIXER>";
638c2ecf20Sopenharmony_ci	}
648c2ecf20Sopenharmony_ci}
658c2ecf20Sopenharmony_ci
668c2ecf20Sopenharmony_cistatic inline u32 sti_mixer_reg_read(struct sti_mixer *mixer, u32 reg_id)
678c2ecf20Sopenharmony_ci{
688c2ecf20Sopenharmony_ci	return readl(mixer->regs + reg_id);
698c2ecf20Sopenharmony_ci}
708c2ecf20Sopenharmony_ci
718c2ecf20Sopenharmony_cistatic inline void sti_mixer_reg_write(struct sti_mixer *mixer,
728c2ecf20Sopenharmony_ci				       u32 reg_id, u32 val)
738c2ecf20Sopenharmony_ci{
748c2ecf20Sopenharmony_ci	writel(val, mixer->regs + reg_id);
758c2ecf20Sopenharmony_ci}
768c2ecf20Sopenharmony_ci
778c2ecf20Sopenharmony_ci#define DBGFS_DUMP(reg) seq_printf(s, "\n  %-25s 0x%08X", #reg, \
788c2ecf20Sopenharmony_ci				   sti_mixer_reg_read(mixer, reg))
798c2ecf20Sopenharmony_ci
808c2ecf20Sopenharmony_cistatic void mixer_dbg_ctl(struct seq_file *s, int val)
818c2ecf20Sopenharmony_ci{
828c2ecf20Sopenharmony_ci	unsigned int i;
838c2ecf20Sopenharmony_ci	int count = 0;
848c2ecf20Sopenharmony_ci	char *const disp_layer[] = {"BKG", "VID0", "VID1", "GDP0",
858c2ecf20Sopenharmony_ci				    "GDP1", "GDP2", "GDP3"};
868c2ecf20Sopenharmony_ci
878c2ecf20Sopenharmony_ci	seq_puts(s, "\tEnabled: ");
888c2ecf20Sopenharmony_ci	for (i = 0; i < 7; i++) {
898c2ecf20Sopenharmony_ci		if (val & 1) {
908c2ecf20Sopenharmony_ci			seq_printf(s, "%s ", disp_layer[i]);
918c2ecf20Sopenharmony_ci			count++;
928c2ecf20Sopenharmony_ci		}
938c2ecf20Sopenharmony_ci		val = val >> 1;
948c2ecf20Sopenharmony_ci	}
958c2ecf20Sopenharmony_ci
968c2ecf20Sopenharmony_ci	val = val >> 2;
978c2ecf20Sopenharmony_ci	if (val & 1) {
988c2ecf20Sopenharmony_ci		seq_puts(s, "CURS ");
998c2ecf20Sopenharmony_ci		count++;
1008c2ecf20Sopenharmony_ci	}
1018c2ecf20Sopenharmony_ci	if (!count)
1028c2ecf20Sopenharmony_ci		seq_puts(s, "Nothing");
1038c2ecf20Sopenharmony_ci}
1048c2ecf20Sopenharmony_ci
1058c2ecf20Sopenharmony_cistatic void mixer_dbg_crb(struct seq_file *s, int val)
1068c2ecf20Sopenharmony_ci{
1078c2ecf20Sopenharmony_ci	int i;
1088c2ecf20Sopenharmony_ci
1098c2ecf20Sopenharmony_ci	seq_puts(s, "\tDepth: ");
1108c2ecf20Sopenharmony_ci	for (i = 0; i < GAM_MIXER_NB_DEPTH_LEVEL; i++) {
1118c2ecf20Sopenharmony_ci		switch (val & GAM_DEPTH_MASK_ID) {
1128c2ecf20Sopenharmony_ci		case GAM_DEPTH_VID0_ID:
1138c2ecf20Sopenharmony_ci			seq_puts(s, "VID0");
1148c2ecf20Sopenharmony_ci			break;
1158c2ecf20Sopenharmony_ci		case GAM_DEPTH_VID1_ID:
1168c2ecf20Sopenharmony_ci			seq_puts(s, "VID1");
1178c2ecf20Sopenharmony_ci			break;
1188c2ecf20Sopenharmony_ci		case GAM_DEPTH_GDP0_ID:
1198c2ecf20Sopenharmony_ci			seq_puts(s, "GDP0");
1208c2ecf20Sopenharmony_ci			break;
1218c2ecf20Sopenharmony_ci		case GAM_DEPTH_GDP1_ID:
1228c2ecf20Sopenharmony_ci			seq_puts(s, "GDP1");
1238c2ecf20Sopenharmony_ci			break;
1248c2ecf20Sopenharmony_ci		case GAM_DEPTH_GDP2_ID:
1258c2ecf20Sopenharmony_ci			seq_puts(s, "GDP2");
1268c2ecf20Sopenharmony_ci			break;
1278c2ecf20Sopenharmony_ci		case GAM_DEPTH_GDP3_ID:
1288c2ecf20Sopenharmony_ci			seq_puts(s, "GDP3");
1298c2ecf20Sopenharmony_ci			break;
1308c2ecf20Sopenharmony_ci		default:
1318c2ecf20Sopenharmony_ci			seq_puts(s, "---");
1328c2ecf20Sopenharmony_ci		}
1338c2ecf20Sopenharmony_ci
1348c2ecf20Sopenharmony_ci		if (i < GAM_MIXER_NB_DEPTH_LEVEL - 1)
1358c2ecf20Sopenharmony_ci			seq_puts(s, " < ");
1368c2ecf20Sopenharmony_ci		val = val >> 3;
1378c2ecf20Sopenharmony_ci	}
1388c2ecf20Sopenharmony_ci}
1398c2ecf20Sopenharmony_ci
1408c2ecf20Sopenharmony_cistatic void mixer_dbg_mxn(struct seq_file *s, void *addr)
1418c2ecf20Sopenharmony_ci{
1428c2ecf20Sopenharmony_ci	int i;
1438c2ecf20Sopenharmony_ci
1448c2ecf20Sopenharmony_ci	for (i = 1; i < 8; i++)
1458c2ecf20Sopenharmony_ci		seq_printf(s, "-0x%08X", (int)readl(addr + i * 4));
1468c2ecf20Sopenharmony_ci}
1478c2ecf20Sopenharmony_ci
1488c2ecf20Sopenharmony_cistatic int mixer_dbg_show(struct seq_file *s, void *arg)
1498c2ecf20Sopenharmony_ci{
1508c2ecf20Sopenharmony_ci	struct drm_info_node *node = s->private;
1518c2ecf20Sopenharmony_ci	struct sti_mixer *mixer = (struct sti_mixer *)node->info_ent->data;
1528c2ecf20Sopenharmony_ci
1538c2ecf20Sopenharmony_ci	seq_printf(s, "%s: (vaddr = 0x%p)",
1548c2ecf20Sopenharmony_ci		   sti_mixer_to_str(mixer), mixer->regs);
1558c2ecf20Sopenharmony_ci
1568c2ecf20Sopenharmony_ci	DBGFS_DUMP(GAM_MIXER_CTL);
1578c2ecf20Sopenharmony_ci	mixer_dbg_ctl(s, sti_mixer_reg_read(mixer, GAM_MIXER_CTL));
1588c2ecf20Sopenharmony_ci	DBGFS_DUMP(GAM_MIXER_BKC);
1598c2ecf20Sopenharmony_ci	DBGFS_DUMP(GAM_MIXER_BCO);
1608c2ecf20Sopenharmony_ci	DBGFS_DUMP(GAM_MIXER_BCS);
1618c2ecf20Sopenharmony_ci	DBGFS_DUMP(GAM_MIXER_AVO);
1628c2ecf20Sopenharmony_ci	DBGFS_DUMP(GAM_MIXER_AVS);
1638c2ecf20Sopenharmony_ci	DBGFS_DUMP(GAM_MIXER_CRB);
1648c2ecf20Sopenharmony_ci	mixer_dbg_crb(s, sti_mixer_reg_read(mixer, GAM_MIXER_CRB));
1658c2ecf20Sopenharmony_ci	DBGFS_DUMP(GAM_MIXER_ACT);
1668c2ecf20Sopenharmony_ci	DBGFS_DUMP(GAM_MIXER_MBP);
1678c2ecf20Sopenharmony_ci	DBGFS_DUMP(GAM_MIXER_MX0);
1688c2ecf20Sopenharmony_ci	mixer_dbg_mxn(s, mixer->regs + GAM_MIXER_MX0);
1698c2ecf20Sopenharmony_ci	seq_putc(s, '\n');
1708c2ecf20Sopenharmony_ci	return 0;
1718c2ecf20Sopenharmony_ci}
1728c2ecf20Sopenharmony_ci
1738c2ecf20Sopenharmony_cistatic struct drm_info_list mixer0_debugfs_files[] = {
1748c2ecf20Sopenharmony_ci	{ "mixer_main", mixer_dbg_show, 0, NULL },
1758c2ecf20Sopenharmony_ci};
1768c2ecf20Sopenharmony_ci
1778c2ecf20Sopenharmony_cistatic struct drm_info_list mixer1_debugfs_files[] = {
1788c2ecf20Sopenharmony_ci	{ "mixer_aux", mixer_dbg_show, 0, NULL },
1798c2ecf20Sopenharmony_ci};
1808c2ecf20Sopenharmony_ci
1818c2ecf20Sopenharmony_civoid sti_mixer_debugfs_init(struct sti_mixer *mixer, struct drm_minor *minor)
1828c2ecf20Sopenharmony_ci{
1838c2ecf20Sopenharmony_ci	unsigned int i;
1848c2ecf20Sopenharmony_ci	struct drm_info_list *mixer_debugfs_files;
1858c2ecf20Sopenharmony_ci	int nb_files;
1868c2ecf20Sopenharmony_ci
1878c2ecf20Sopenharmony_ci	switch (mixer->id) {
1888c2ecf20Sopenharmony_ci	case STI_MIXER_MAIN:
1898c2ecf20Sopenharmony_ci		mixer_debugfs_files = mixer0_debugfs_files;
1908c2ecf20Sopenharmony_ci		nb_files = ARRAY_SIZE(mixer0_debugfs_files);
1918c2ecf20Sopenharmony_ci		break;
1928c2ecf20Sopenharmony_ci	case STI_MIXER_AUX:
1938c2ecf20Sopenharmony_ci		mixer_debugfs_files = mixer1_debugfs_files;
1948c2ecf20Sopenharmony_ci		nb_files = ARRAY_SIZE(mixer1_debugfs_files);
1958c2ecf20Sopenharmony_ci		break;
1968c2ecf20Sopenharmony_ci	default:
1978c2ecf20Sopenharmony_ci		return;
1988c2ecf20Sopenharmony_ci	}
1998c2ecf20Sopenharmony_ci
2008c2ecf20Sopenharmony_ci	for (i = 0; i < nb_files; i++)
2018c2ecf20Sopenharmony_ci		mixer_debugfs_files[i].data = mixer;
2028c2ecf20Sopenharmony_ci
2038c2ecf20Sopenharmony_ci	drm_debugfs_create_files(mixer_debugfs_files,
2048c2ecf20Sopenharmony_ci				 nb_files,
2058c2ecf20Sopenharmony_ci				 minor->debugfs_root, minor);
2068c2ecf20Sopenharmony_ci}
2078c2ecf20Sopenharmony_ci
2088c2ecf20Sopenharmony_civoid sti_mixer_set_background_status(struct sti_mixer *mixer, bool enable)
2098c2ecf20Sopenharmony_ci{
2108c2ecf20Sopenharmony_ci	u32 val = sti_mixer_reg_read(mixer, GAM_MIXER_CTL);
2118c2ecf20Sopenharmony_ci
2128c2ecf20Sopenharmony_ci	val &= ~GAM_CTL_BACK_MASK;
2138c2ecf20Sopenharmony_ci	val |= enable;
2148c2ecf20Sopenharmony_ci	sti_mixer_reg_write(mixer, GAM_MIXER_CTL, val);
2158c2ecf20Sopenharmony_ci}
2168c2ecf20Sopenharmony_ci
2178c2ecf20Sopenharmony_cistatic void sti_mixer_set_background_color(struct sti_mixer *mixer,
2188c2ecf20Sopenharmony_ci					   unsigned int rgb)
2198c2ecf20Sopenharmony_ci{
2208c2ecf20Sopenharmony_ci	sti_mixer_reg_write(mixer, GAM_MIXER_BKC, rgb);
2218c2ecf20Sopenharmony_ci}
2228c2ecf20Sopenharmony_ci
2238c2ecf20Sopenharmony_cistatic void sti_mixer_set_background_area(struct sti_mixer *mixer,
2248c2ecf20Sopenharmony_ci					  struct drm_display_mode *mode)
2258c2ecf20Sopenharmony_ci{
2268c2ecf20Sopenharmony_ci	u32 ydo, xdo, yds, xds;
2278c2ecf20Sopenharmony_ci
2288c2ecf20Sopenharmony_ci	ydo = sti_vtg_get_line_number(*mode, 0);
2298c2ecf20Sopenharmony_ci	yds = sti_vtg_get_line_number(*mode, mode->vdisplay - 1);
2308c2ecf20Sopenharmony_ci	xdo = sti_vtg_get_pixel_number(*mode, 0);
2318c2ecf20Sopenharmony_ci	xds = sti_vtg_get_pixel_number(*mode, mode->hdisplay - 1);
2328c2ecf20Sopenharmony_ci
2338c2ecf20Sopenharmony_ci	sti_mixer_reg_write(mixer, GAM_MIXER_BCO, ydo << 16 | xdo);
2348c2ecf20Sopenharmony_ci	sti_mixer_reg_write(mixer, GAM_MIXER_BCS, yds << 16 | xds);
2358c2ecf20Sopenharmony_ci}
2368c2ecf20Sopenharmony_ci
2378c2ecf20Sopenharmony_ciint sti_mixer_set_plane_depth(struct sti_mixer *mixer, struct sti_plane *plane)
2388c2ecf20Sopenharmony_ci{
2398c2ecf20Sopenharmony_ci	int plane_id, depth = plane->drm_plane.state->normalized_zpos;
2408c2ecf20Sopenharmony_ci	unsigned int i;
2418c2ecf20Sopenharmony_ci	u32 mask, val;
2428c2ecf20Sopenharmony_ci
2438c2ecf20Sopenharmony_ci	switch (plane->desc) {
2448c2ecf20Sopenharmony_ci	case STI_GDP_0:
2458c2ecf20Sopenharmony_ci		plane_id = GAM_DEPTH_GDP0_ID;
2468c2ecf20Sopenharmony_ci		break;
2478c2ecf20Sopenharmony_ci	case STI_GDP_1:
2488c2ecf20Sopenharmony_ci		plane_id = GAM_DEPTH_GDP1_ID;
2498c2ecf20Sopenharmony_ci		break;
2508c2ecf20Sopenharmony_ci	case STI_GDP_2:
2518c2ecf20Sopenharmony_ci		plane_id = GAM_DEPTH_GDP2_ID;
2528c2ecf20Sopenharmony_ci		break;
2538c2ecf20Sopenharmony_ci	case STI_GDP_3:
2548c2ecf20Sopenharmony_ci		plane_id = GAM_DEPTH_GDP3_ID;
2558c2ecf20Sopenharmony_ci		break;
2568c2ecf20Sopenharmony_ci	case STI_HQVDP_0:
2578c2ecf20Sopenharmony_ci		plane_id = GAM_DEPTH_VID0_ID;
2588c2ecf20Sopenharmony_ci		break;
2598c2ecf20Sopenharmony_ci	case STI_CURSOR:
2608c2ecf20Sopenharmony_ci		/* no need to set depth for cursor */
2618c2ecf20Sopenharmony_ci		return 0;
2628c2ecf20Sopenharmony_ci	default:
2638c2ecf20Sopenharmony_ci		DRM_ERROR("Unknown plane %d\n", plane->desc);
2648c2ecf20Sopenharmony_ci		return 1;
2658c2ecf20Sopenharmony_ci	}
2668c2ecf20Sopenharmony_ci
2678c2ecf20Sopenharmony_ci	/* Search if a previous depth was already assigned to the plane */
2688c2ecf20Sopenharmony_ci	val = sti_mixer_reg_read(mixer, GAM_MIXER_CRB);
2698c2ecf20Sopenharmony_ci	for (i = 0; i < GAM_MIXER_NB_DEPTH_LEVEL; i++) {
2708c2ecf20Sopenharmony_ci		mask = GAM_DEPTH_MASK_ID << (3 * i);
2718c2ecf20Sopenharmony_ci		if ((val & mask) == plane_id << (3 * i))
2728c2ecf20Sopenharmony_ci			break;
2738c2ecf20Sopenharmony_ci	}
2748c2ecf20Sopenharmony_ci
2758c2ecf20Sopenharmony_ci	mask |= GAM_DEPTH_MASK_ID << (3 * depth);
2768c2ecf20Sopenharmony_ci	plane_id = plane_id << (3 * depth);
2778c2ecf20Sopenharmony_ci
2788c2ecf20Sopenharmony_ci	DRM_DEBUG_DRIVER("%s %s depth=%d\n", sti_mixer_to_str(mixer),
2798c2ecf20Sopenharmony_ci			 sti_plane_to_str(plane), depth);
2808c2ecf20Sopenharmony_ci	dev_dbg(mixer->dev, "GAM_MIXER_CRB val 0x%x mask 0x%x\n",
2818c2ecf20Sopenharmony_ci		plane_id, mask);
2828c2ecf20Sopenharmony_ci
2838c2ecf20Sopenharmony_ci	val &= ~mask;
2848c2ecf20Sopenharmony_ci	val |= plane_id;
2858c2ecf20Sopenharmony_ci	sti_mixer_reg_write(mixer, GAM_MIXER_CRB, val);
2868c2ecf20Sopenharmony_ci
2878c2ecf20Sopenharmony_ci	dev_dbg(mixer->dev, "Read GAM_MIXER_CRB 0x%x\n",
2888c2ecf20Sopenharmony_ci		sti_mixer_reg_read(mixer, GAM_MIXER_CRB));
2898c2ecf20Sopenharmony_ci	return 0;
2908c2ecf20Sopenharmony_ci}
2918c2ecf20Sopenharmony_ci
2928c2ecf20Sopenharmony_ciint sti_mixer_active_video_area(struct sti_mixer *mixer,
2938c2ecf20Sopenharmony_ci				struct drm_display_mode *mode)
2948c2ecf20Sopenharmony_ci{
2958c2ecf20Sopenharmony_ci	u32 ydo, xdo, yds, xds;
2968c2ecf20Sopenharmony_ci
2978c2ecf20Sopenharmony_ci	ydo = sti_vtg_get_line_number(*mode, 0);
2988c2ecf20Sopenharmony_ci	yds = sti_vtg_get_line_number(*mode, mode->vdisplay - 1);
2998c2ecf20Sopenharmony_ci	xdo = sti_vtg_get_pixel_number(*mode, 0);
3008c2ecf20Sopenharmony_ci	xds = sti_vtg_get_pixel_number(*mode, mode->hdisplay - 1);
3018c2ecf20Sopenharmony_ci
3028c2ecf20Sopenharmony_ci	DRM_DEBUG_DRIVER("%s active video area xdo:%d ydo:%d xds:%d yds:%d\n",
3038c2ecf20Sopenharmony_ci			 sti_mixer_to_str(mixer), xdo, ydo, xds, yds);
3048c2ecf20Sopenharmony_ci	sti_mixer_reg_write(mixer, GAM_MIXER_AVO, ydo << 16 | xdo);
3058c2ecf20Sopenharmony_ci	sti_mixer_reg_write(mixer, GAM_MIXER_AVS, yds << 16 | xds);
3068c2ecf20Sopenharmony_ci
3078c2ecf20Sopenharmony_ci	sti_mixer_set_background_color(mixer, bkg_color);
3088c2ecf20Sopenharmony_ci
3098c2ecf20Sopenharmony_ci	sti_mixer_set_background_area(mixer, mode);
3108c2ecf20Sopenharmony_ci	sti_mixer_set_background_status(mixer, true);
3118c2ecf20Sopenharmony_ci	return 0;
3128c2ecf20Sopenharmony_ci}
3138c2ecf20Sopenharmony_ci
3148c2ecf20Sopenharmony_cistatic u32 sti_mixer_get_plane_mask(struct sti_plane *plane)
3158c2ecf20Sopenharmony_ci{
3168c2ecf20Sopenharmony_ci	switch (plane->desc) {
3178c2ecf20Sopenharmony_ci	case STI_BACK:
3188c2ecf20Sopenharmony_ci		return GAM_CTL_BACK_MASK;
3198c2ecf20Sopenharmony_ci	case STI_GDP_0:
3208c2ecf20Sopenharmony_ci		return GAM_CTL_GDP0_MASK;
3218c2ecf20Sopenharmony_ci	case STI_GDP_1:
3228c2ecf20Sopenharmony_ci		return GAM_CTL_GDP1_MASK;
3238c2ecf20Sopenharmony_ci	case STI_GDP_2:
3248c2ecf20Sopenharmony_ci		return GAM_CTL_GDP2_MASK;
3258c2ecf20Sopenharmony_ci	case STI_GDP_3:
3268c2ecf20Sopenharmony_ci		return GAM_CTL_GDP3_MASK;
3278c2ecf20Sopenharmony_ci	case STI_HQVDP_0:
3288c2ecf20Sopenharmony_ci		return GAM_CTL_VID0_MASK;
3298c2ecf20Sopenharmony_ci	case STI_CURSOR:
3308c2ecf20Sopenharmony_ci		return GAM_CTL_CURSOR_MASK;
3318c2ecf20Sopenharmony_ci	default:
3328c2ecf20Sopenharmony_ci		return 0;
3338c2ecf20Sopenharmony_ci	}
3348c2ecf20Sopenharmony_ci}
3358c2ecf20Sopenharmony_ci
3368c2ecf20Sopenharmony_ciint sti_mixer_set_plane_status(struct sti_mixer *mixer,
3378c2ecf20Sopenharmony_ci			       struct sti_plane *plane, bool status)
3388c2ecf20Sopenharmony_ci{
3398c2ecf20Sopenharmony_ci	u32 mask, val;
3408c2ecf20Sopenharmony_ci
3418c2ecf20Sopenharmony_ci	DRM_DEBUG_DRIVER("%s %s %s\n", status ? "enable" : "disable",
3428c2ecf20Sopenharmony_ci			 sti_mixer_to_str(mixer), sti_plane_to_str(plane));
3438c2ecf20Sopenharmony_ci
3448c2ecf20Sopenharmony_ci	mask = sti_mixer_get_plane_mask(plane);
3458c2ecf20Sopenharmony_ci	if (!mask) {
3468c2ecf20Sopenharmony_ci		DRM_ERROR("Can't find layer mask\n");
3478c2ecf20Sopenharmony_ci		return -EINVAL;
3488c2ecf20Sopenharmony_ci	}
3498c2ecf20Sopenharmony_ci
3508c2ecf20Sopenharmony_ci	val = sti_mixer_reg_read(mixer, GAM_MIXER_CTL);
3518c2ecf20Sopenharmony_ci	val &= ~mask;
3528c2ecf20Sopenharmony_ci	val |= status ? mask : 0;
3538c2ecf20Sopenharmony_ci	sti_mixer_reg_write(mixer, GAM_MIXER_CTL, val);
3548c2ecf20Sopenharmony_ci
3558c2ecf20Sopenharmony_ci	return 0;
3568c2ecf20Sopenharmony_ci}
3578c2ecf20Sopenharmony_ci
3588c2ecf20Sopenharmony_cistruct sti_mixer *sti_mixer_create(struct device *dev,
3598c2ecf20Sopenharmony_ci				   struct drm_device *drm_dev,
3608c2ecf20Sopenharmony_ci				   int id,
3618c2ecf20Sopenharmony_ci				   void __iomem *baseaddr)
3628c2ecf20Sopenharmony_ci{
3638c2ecf20Sopenharmony_ci	struct sti_mixer *mixer = devm_kzalloc(dev, sizeof(*mixer), GFP_KERNEL);
3648c2ecf20Sopenharmony_ci
3658c2ecf20Sopenharmony_ci	dev_dbg(dev, "%s\n", __func__);
3668c2ecf20Sopenharmony_ci	if (!mixer) {
3678c2ecf20Sopenharmony_ci		DRM_ERROR("Failed to allocated memory for mixer\n");
3688c2ecf20Sopenharmony_ci		return NULL;
3698c2ecf20Sopenharmony_ci	}
3708c2ecf20Sopenharmony_ci	mixer->regs = baseaddr;
3718c2ecf20Sopenharmony_ci	mixer->dev = dev;
3728c2ecf20Sopenharmony_ci	mixer->id = id;
3738c2ecf20Sopenharmony_ci
3748c2ecf20Sopenharmony_ci	DRM_DEBUG_DRIVER("%s created. Regs=%p\n",
3758c2ecf20Sopenharmony_ci			 sti_mixer_to_str(mixer), mixer->regs);
3768c2ecf20Sopenharmony_ci
3778c2ecf20Sopenharmony_ci	return mixer;
3788c2ecf20Sopenharmony_ci}
379