162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Copyright (C) STMicroelectronics SA 2014 462306a36Sopenharmony_ci * Authors: Benjamin Gaignard <benjamin.gaignard@st.com> 562306a36Sopenharmony_ci * Fabien Dessenne <fabien.dessenne@st.com> 662306a36Sopenharmony_ci * for STMicroelectronics. 762306a36Sopenharmony_ci */ 862306a36Sopenharmony_ci 962306a36Sopenharmony_ci#include <linux/moduleparam.h> 1062306a36Sopenharmony_ci#include <linux/seq_file.h> 1162306a36Sopenharmony_ci 1262306a36Sopenharmony_ci#include <drm/drm_print.h> 1362306a36Sopenharmony_ci 1462306a36Sopenharmony_ci#include "sti_compositor.h" 1562306a36Sopenharmony_ci#include "sti_mixer.h" 1662306a36Sopenharmony_ci#include "sti_vtg.h" 1762306a36Sopenharmony_ci 1862306a36Sopenharmony_ci/* Module parameter to set the background color of the mixer */ 1962306a36Sopenharmony_cistatic unsigned int bkg_color = 0x000000; 2062306a36Sopenharmony_ciMODULE_PARM_DESC(bkgcolor, "Value of the background color 0xRRGGBB"); 2162306a36Sopenharmony_cimodule_param_named(bkgcolor, bkg_color, int, 0644); 2262306a36Sopenharmony_ci 2362306a36Sopenharmony_ci/* regs offset */ 2462306a36Sopenharmony_ci#define GAM_MIXER_CTL 0x00 2562306a36Sopenharmony_ci#define GAM_MIXER_BKC 0x04 2662306a36Sopenharmony_ci#define GAM_MIXER_BCO 0x0C 2762306a36Sopenharmony_ci#define GAM_MIXER_BCS 0x10 2862306a36Sopenharmony_ci#define GAM_MIXER_AVO 0x28 2962306a36Sopenharmony_ci#define GAM_MIXER_AVS 0x2C 3062306a36Sopenharmony_ci#define GAM_MIXER_CRB 0x34 3162306a36Sopenharmony_ci#define GAM_MIXER_ACT 0x38 3262306a36Sopenharmony_ci#define GAM_MIXER_MBP 0x3C 3362306a36Sopenharmony_ci#define GAM_MIXER_MX0 0x80 3462306a36Sopenharmony_ci 3562306a36Sopenharmony_ci/* id for depth of CRB reg */ 3662306a36Sopenharmony_ci#define GAM_DEPTH_VID0_ID 1 3762306a36Sopenharmony_ci#define GAM_DEPTH_VID1_ID 2 3862306a36Sopenharmony_ci#define GAM_DEPTH_GDP0_ID 3 3962306a36Sopenharmony_ci#define GAM_DEPTH_GDP1_ID 4 4062306a36Sopenharmony_ci#define GAM_DEPTH_GDP2_ID 5 4162306a36Sopenharmony_ci#define GAM_DEPTH_GDP3_ID 6 4262306a36Sopenharmony_ci#define GAM_DEPTH_MASK_ID 7 4362306a36Sopenharmony_ci 4462306a36Sopenharmony_ci/* mask in CTL reg */ 4562306a36Sopenharmony_ci#define GAM_CTL_BACK_MASK BIT(0) 4662306a36Sopenharmony_ci#define GAM_CTL_VID0_MASK BIT(1) 4762306a36Sopenharmony_ci#define GAM_CTL_VID1_MASK BIT(2) 4862306a36Sopenharmony_ci#define GAM_CTL_GDP0_MASK BIT(3) 4962306a36Sopenharmony_ci#define GAM_CTL_GDP1_MASK BIT(4) 5062306a36Sopenharmony_ci#define GAM_CTL_GDP2_MASK BIT(5) 5162306a36Sopenharmony_ci#define GAM_CTL_GDP3_MASK BIT(6) 5262306a36Sopenharmony_ci#define GAM_CTL_CURSOR_MASK BIT(9) 5362306a36Sopenharmony_ci 5462306a36Sopenharmony_ciconst char *sti_mixer_to_str(struct sti_mixer *mixer) 5562306a36Sopenharmony_ci{ 5662306a36Sopenharmony_ci switch (mixer->id) { 5762306a36Sopenharmony_ci case STI_MIXER_MAIN: 5862306a36Sopenharmony_ci return "MAIN_MIXER"; 5962306a36Sopenharmony_ci case STI_MIXER_AUX: 6062306a36Sopenharmony_ci return "AUX_MIXER"; 6162306a36Sopenharmony_ci default: 6262306a36Sopenharmony_ci return "<UNKNOWN MIXER>"; 6362306a36Sopenharmony_ci } 6462306a36Sopenharmony_ci} 6562306a36Sopenharmony_ci 6662306a36Sopenharmony_cistatic inline u32 sti_mixer_reg_read(struct sti_mixer *mixer, u32 reg_id) 6762306a36Sopenharmony_ci{ 6862306a36Sopenharmony_ci return readl(mixer->regs + reg_id); 6962306a36Sopenharmony_ci} 7062306a36Sopenharmony_ci 7162306a36Sopenharmony_cistatic inline void sti_mixer_reg_write(struct sti_mixer *mixer, 7262306a36Sopenharmony_ci u32 reg_id, u32 val) 7362306a36Sopenharmony_ci{ 7462306a36Sopenharmony_ci writel(val, mixer->regs + reg_id); 7562306a36Sopenharmony_ci} 7662306a36Sopenharmony_ci 7762306a36Sopenharmony_ci#define DBGFS_DUMP(reg) seq_printf(s, "\n %-25s 0x%08X", #reg, \ 7862306a36Sopenharmony_ci sti_mixer_reg_read(mixer, reg)) 7962306a36Sopenharmony_ci 8062306a36Sopenharmony_cistatic void mixer_dbg_ctl(struct seq_file *s, int val) 8162306a36Sopenharmony_ci{ 8262306a36Sopenharmony_ci unsigned int i; 8362306a36Sopenharmony_ci int count = 0; 8462306a36Sopenharmony_ci char *const disp_layer[] = {"BKG", "VID0", "VID1", "GDP0", 8562306a36Sopenharmony_ci "GDP1", "GDP2", "GDP3"}; 8662306a36Sopenharmony_ci 8762306a36Sopenharmony_ci seq_puts(s, "\tEnabled: "); 8862306a36Sopenharmony_ci for (i = 0; i < 7; i++) { 8962306a36Sopenharmony_ci if (val & 1) { 9062306a36Sopenharmony_ci seq_printf(s, "%s ", disp_layer[i]); 9162306a36Sopenharmony_ci count++; 9262306a36Sopenharmony_ci } 9362306a36Sopenharmony_ci val = val >> 1; 9462306a36Sopenharmony_ci } 9562306a36Sopenharmony_ci 9662306a36Sopenharmony_ci val = val >> 2; 9762306a36Sopenharmony_ci if (val & 1) { 9862306a36Sopenharmony_ci seq_puts(s, "CURS "); 9962306a36Sopenharmony_ci count++; 10062306a36Sopenharmony_ci } 10162306a36Sopenharmony_ci if (!count) 10262306a36Sopenharmony_ci seq_puts(s, "Nothing"); 10362306a36Sopenharmony_ci} 10462306a36Sopenharmony_ci 10562306a36Sopenharmony_cistatic void mixer_dbg_crb(struct seq_file *s, int val) 10662306a36Sopenharmony_ci{ 10762306a36Sopenharmony_ci int i; 10862306a36Sopenharmony_ci 10962306a36Sopenharmony_ci seq_puts(s, "\tDepth: "); 11062306a36Sopenharmony_ci for (i = 0; i < GAM_MIXER_NB_DEPTH_LEVEL; i++) { 11162306a36Sopenharmony_ci switch (val & GAM_DEPTH_MASK_ID) { 11262306a36Sopenharmony_ci case GAM_DEPTH_VID0_ID: 11362306a36Sopenharmony_ci seq_puts(s, "VID0"); 11462306a36Sopenharmony_ci break; 11562306a36Sopenharmony_ci case GAM_DEPTH_VID1_ID: 11662306a36Sopenharmony_ci seq_puts(s, "VID1"); 11762306a36Sopenharmony_ci break; 11862306a36Sopenharmony_ci case GAM_DEPTH_GDP0_ID: 11962306a36Sopenharmony_ci seq_puts(s, "GDP0"); 12062306a36Sopenharmony_ci break; 12162306a36Sopenharmony_ci case GAM_DEPTH_GDP1_ID: 12262306a36Sopenharmony_ci seq_puts(s, "GDP1"); 12362306a36Sopenharmony_ci break; 12462306a36Sopenharmony_ci case GAM_DEPTH_GDP2_ID: 12562306a36Sopenharmony_ci seq_puts(s, "GDP2"); 12662306a36Sopenharmony_ci break; 12762306a36Sopenharmony_ci case GAM_DEPTH_GDP3_ID: 12862306a36Sopenharmony_ci seq_puts(s, "GDP3"); 12962306a36Sopenharmony_ci break; 13062306a36Sopenharmony_ci default: 13162306a36Sopenharmony_ci seq_puts(s, "---"); 13262306a36Sopenharmony_ci } 13362306a36Sopenharmony_ci 13462306a36Sopenharmony_ci if (i < GAM_MIXER_NB_DEPTH_LEVEL - 1) 13562306a36Sopenharmony_ci seq_puts(s, " < "); 13662306a36Sopenharmony_ci val = val >> 3; 13762306a36Sopenharmony_ci } 13862306a36Sopenharmony_ci} 13962306a36Sopenharmony_ci 14062306a36Sopenharmony_cistatic void mixer_dbg_mxn(struct seq_file *s, void *addr) 14162306a36Sopenharmony_ci{ 14262306a36Sopenharmony_ci int i; 14362306a36Sopenharmony_ci 14462306a36Sopenharmony_ci for (i = 1; i < 8; i++) 14562306a36Sopenharmony_ci seq_printf(s, "-0x%08X", (int)readl(addr + i * 4)); 14662306a36Sopenharmony_ci} 14762306a36Sopenharmony_ci 14862306a36Sopenharmony_cistatic int mixer_dbg_show(struct seq_file *s, void *arg) 14962306a36Sopenharmony_ci{ 15062306a36Sopenharmony_ci struct drm_info_node *node = s->private; 15162306a36Sopenharmony_ci struct sti_mixer *mixer = (struct sti_mixer *)node->info_ent->data; 15262306a36Sopenharmony_ci 15362306a36Sopenharmony_ci seq_printf(s, "%s: (vaddr = 0x%p)", 15462306a36Sopenharmony_ci sti_mixer_to_str(mixer), mixer->regs); 15562306a36Sopenharmony_ci 15662306a36Sopenharmony_ci DBGFS_DUMP(GAM_MIXER_CTL); 15762306a36Sopenharmony_ci mixer_dbg_ctl(s, sti_mixer_reg_read(mixer, GAM_MIXER_CTL)); 15862306a36Sopenharmony_ci DBGFS_DUMP(GAM_MIXER_BKC); 15962306a36Sopenharmony_ci DBGFS_DUMP(GAM_MIXER_BCO); 16062306a36Sopenharmony_ci DBGFS_DUMP(GAM_MIXER_BCS); 16162306a36Sopenharmony_ci DBGFS_DUMP(GAM_MIXER_AVO); 16262306a36Sopenharmony_ci DBGFS_DUMP(GAM_MIXER_AVS); 16362306a36Sopenharmony_ci DBGFS_DUMP(GAM_MIXER_CRB); 16462306a36Sopenharmony_ci mixer_dbg_crb(s, sti_mixer_reg_read(mixer, GAM_MIXER_CRB)); 16562306a36Sopenharmony_ci DBGFS_DUMP(GAM_MIXER_ACT); 16662306a36Sopenharmony_ci DBGFS_DUMP(GAM_MIXER_MBP); 16762306a36Sopenharmony_ci DBGFS_DUMP(GAM_MIXER_MX0); 16862306a36Sopenharmony_ci mixer_dbg_mxn(s, mixer->regs + GAM_MIXER_MX0); 16962306a36Sopenharmony_ci seq_putc(s, '\n'); 17062306a36Sopenharmony_ci return 0; 17162306a36Sopenharmony_ci} 17262306a36Sopenharmony_ci 17362306a36Sopenharmony_cistatic struct drm_info_list mixer0_debugfs_files[] = { 17462306a36Sopenharmony_ci { "mixer_main", mixer_dbg_show, 0, NULL }, 17562306a36Sopenharmony_ci}; 17662306a36Sopenharmony_ci 17762306a36Sopenharmony_cistatic struct drm_info_list mixer1_debugfs_files[] = { 17862306a36Sopenharmony_ci { "mixer_aux", mixer_dbg_show, 0, NULL }, 17962306a36Sopenharmony_ci}; 18062306a36Sopenharmony_ci 18162306a36Sopenharmony_civoid sti_mixer_debugfs_init(struct sti_mixer *mixer, struct drm_minor *minor) 18262306a36Sopenharmony_ci{ 18362306a36Sopenharmony_ci unsigned int i; 18462306a36Sopenharmony_ci struct drm_info_list *mixer_debugfs_files; 18562306a36Sopenharmony_ci int nb_files; 18662306a36Sopenharmony_ci 18762306a36Sopenharmony_ci switch (mixer->id) { 18862306a36Sopenharmony_ci case STI_MIXER_MAIN: 18962306a36Sopenharmony_ci mixer_debugfs_files = mixer0_debugfs_files; 19062306a36Sopenharmony_ci nb_files = ARRAY_SIZE(mixer0_debugfs_files); 19162306a36Sopenharmony_ci break; 19262306a36Sopenharmony_ci case STI_MIXER_AUX: 19362306a36Sopenharmony_ci mixer_debugfs_files = mixer1_debugfs_files; 19462306a36Sopenharmony_ci nb_files = ARRAY_SIZE(mixer1_debugfs_files); 19562306a36Sopenharmony_ci break; 19662306a36Sopenharmony_ci default: 19762306a36Sopenharmony_ci return; 19862306a36Sopenharmony_ci } 19962306a36Sopenharmony_ci 20062306a36Sopenharmony_ci for (i = 0; i < nb_files; i++) 20162306a36Sopenharmony_ci mixer_debugfs_files[i].data = mixer; 20262306a36Sopenharmony_ci 20362306a36Sopenharmony_ci drm_debugfs_create_files(mixer_debugfs_files, 20462306a36Sopenharmony_ci nb_files, 20562306a36Sopenharmony_ci minor->debugfs_root, minor); 20662306a36Sopenharmony_ci} 20762306a36Sopenharmony_ci 20862306a36Sopenharmony_civoid sti_mixer_set_background_status(struct sti_mixer *mixer, bool enable) 20962306a36Sopenharmony_ci{ 21062306a36Sopenharmony_ci u32 val = sti_mixer_reg_read(mixer, GAM_MIXER_CTL); 21162306a36Sopenharmony_ci 21262306a36Sopenharmony_ci val &= ~GAM_CTL_BACK_MASK; 21362306a36Sopenharmony_ci val |= enable; 21462306a36Sopenharmony_ci sti_mixer_reg_write(mixer, GAM_MIXER_CTL, val); 21562306a36Sopenharmony_ci} 21662306a36Sopenharmony_ci 21762306a36Sopenharmony_cistatic void sti_mixer_set_background_color(struct sti_mixer *mixer, 21862306a36Sopenharmony_ci unsigned int rgb) 21962306a36Sopenharmony_ci{ 22062306a36Sopenharmony_ci sti_mixer_reg_write(mixer, GAM_MIXER_BKC, rgb); 22162306a36Sopenharmony_ci} 22262306a36Sopenharmony_ci 22362306a36Sopenharmony_cistatic void sti_mixer_set_background_area(struct sti_mixer *mixer, 22462306a36Sopenharmony_ci struct drm_display_mode *mode) 22562306a36Sopenharmony_ci{ 22662306a36Sopenharmony_ci u32 ydo, xdo, yds, xds; 22762306a36Sopenharmony_ci 22862306a36Sopenharmony_ci ydo = sti_vtg_get_line_number(*mode, 0); 22962306a36Sopenharmony_ci yds = sti_vtg_get_line_number(*mode, mode->vdisplay - 1); 23062306a36Sopenharmony_ci xdo = sti_vtg_get_pixel_number(*mode, 0); 23162306a36Sopenharmony_ci xds = sti_vtg_get_pixel_number(*mode, mode->hdisplay - 1); 23262306a36Sopenharmony_ci 23362306a36Sopenharmony_ci sti_mixer_reg_write(mixer, GAM_MIXER_BCO, ydo << 16 | xdo); 23462306a36Sopenharmony_ci sti_mixer_reg_write(mixer, GAM_MIXER_BCS, yds << 16 | xds); 23562306a36Sopenharmony_ci} 23662306a36Sopenharmony_ci 23762306a36Sopenharmony_ciint sti_mixer_set_plane_depth(struct sti_mixer *mixer, struct sti_plane *plane) 23862306a36Sopenharmony_ci{ 23962306a36Sopenharmony_ci int plane_id, depth = plane->drm_plane.state->normalized_zpos; 24062306a36Sopenharmony_ci unsigned int i; 24162306a36Sopenharmony_ci u32 mask, val; 24262306a36Sopenharmony_ci 24362306a36Sopenharmony_ci switch (plane->desc) { 24462306a36Sopenharmony_ci case STI_GDP_0: 24562306a36Sopenharmony_ci plane_id = GAM_DEPTH_GDP0_ID; 24662306a36Sopenharmony_ci break; 24762306a36Sopenharmony_ci case STI_GDP_1: 24862306a36Sopenharmony_ci plane_id = GAM_DEPTH_GDP1_ID; 24962306a36Sopenharmony_ci break; 25062306a36Sopenharmony_ci case STI_GDP_2: 25162306a36Sopenharmony_ci plane_id = GAM_DEPTH_GDP2_ID; 25262306a36Sopenharmony_ci break; 25362306a36Sopenharmony_ci case STI_GDP_3: 25462306a36Sopenharmony_ci plane_id = GAM_DEPTH_GDP3_ID; 25562306a36Sopenharmony_ci break; 25662306a36Sopenharmony_ci case STI_HQVDP_0: 25762306a36Sopenharmony_ci plane_id = GAM_DEPTH_VID0_ID; 25862306a36Sopenharmony_ci break; 25962306a36Sopenharmony_ci case STI_CURSOR: 26062306a36Sopenharmony_ci /* no need to set depth for cursor */ 26162306a36Sopenharmony_ci return 0; 26262306a36Sopenharmony_ci default: 26362306a36Sopenharmony_ci DRM_ERROR("Unknown plane %d\n", plane->desc); 26462306a36Sopenharmony_ci return 1; 26562306a36Sopenharmony_ci } 26662306a36Sopenharmony_ci 26762306a36Sopenharmony_ci /* Search if a previous depth was already assigned to the plane */ 26862306a36Sopenharmony_ci val = sti_mixer_reg_read(mixer, GAM_MIXER_CRB); 26962306a36Sopenharmony_ci for (i = 0; i < GAM_MIXER_NB_DEPTH_LEVEL; i++) { 27062306a36Sopenharmony_ci mask = GAM_DEPTH_MASK_ID << (3 * i); 27162306a36Sopenharmony_ci if ((val & mask) == plane_id << (3 * i)) 27262306a36Sopenharmony_ci break; 27362306a36Sopenharmony_ci } 27462306a36Sopenharmony_ci 27562306a36Sopenharmony_ci mask |= GAM_DEPTH_MASK_ID << (3 * depth); 27662306a36Sopenharmony_ci plane_id = plane_id << (3 * depth); 27762306a36Sopenharmony_ci 27862306a36Sopenharmony_ci DRM_DEBUG_DRIVER("%s %s depth=%d\n", sti_mixer_to_str(mixer), 27962306a36Sopenharmony_ci sti_plane_to_str(plane), depth); 28062306a36Sopenharmony_ci dev_dbg(mixer->dev, "GAM_MIXER_CRB val 0x%x mask 0x%x\n", 28162306a36Sopenharmony_ci plane_id, mask); 28262306a36Sopenharmony_ci 28362306a36Sopenharmony_ci val &= ~mask; 28462306a36Sopenharmony_ci val |= plane_id; 28562306a36Sopenharmony_ci sti_mixer_reg_write(mixer, GAM_MIXER_CRB, val); 28662306a36Sopenharmony_ci 28762306a36Sopenharmony_ci dev_dbg(mixer->dev, "Read GAM_MIXER_CRB 0x%x\n", 28862306a36Sopenharmony_ci sti_mixer_reg_read(mixer, GAM_MIXER_CRB)); 28962306a36Sopenharmony_ci return 0; 29062306a36Sopenharmony_ci} 29162306a36Sopenharmony_ci 29262306a36Sopenharmony_ciint sti_mixer_active_video_area(struct sti_mixer *mixer, 29362306a36Sopenharmony_ci struct drm_display_mode *mode) 29462306a36Sopenharmony_ci{ 29562306a36Sopenharmony_ci u32 ydo, xdo, yds, xds; 29662306a36Sopenharmony_ci 29762306a36Sopenharmony_ci ydo = sti_vtg_get_line_number(*mode, 0); 29862306a36Sopenharmony_ci yds = sti_vtg_get_line_number(*mode, mode->vdisplay - 1); 29962306a36Sopenharmony_ci xdo = sti_vtg_get_pixel_number(*mode, 0); 30062306a36Sopenharmony_ci xds = sti_vtg_get_pixel_number(*mode, mode->hdisplay - 1); 30162306a36Sopenharmony_ci 30262306a36Sopenharmony_ci DRM_DEBUG_DRIVER("%s active video area xdo:%d ydo:%d xds:%d yds:%d\n", 30362306a36Sopenharmony_ci sti_mixer_to_str(mixer), xdo, ydo, xds, yds); 30462306a36Sopenharmony_ci sti_mixer_reg_write(mixer, GAM_MIXER_AVO, ydo << 16 | xdo); 30562306a36Sopenharmony_ci sti_mixer_reg_write(mixer, GAM_MIXER_AVS, yds << 16 | xds); 30662306a36Sopenharmony_ci 30762306a36Sopenharmony_ci sti_mixer_set_background_color(mixer, bkg_color); 30862306a36Sopenharmony_ci 30962306a36Sopenharmony_ci sti_mixer_set_background_area(mixer, mode); 31062306a36Sopenharmony_ci sti_mixer_set_background_status(mixer, true); 31162306a36Sopenharmony_ci return 0; 31262306a36Sopenharmony_ci} 31362306a36Sopenharmony_ci 31462306a36Sopenharmony_cistatic u32 sti_mixer_get_plane_mask(struct sti_plane *plane) 31562306a36Sopenharmony_ci{ 31662306a36Sopenharmony_ci switch (plane->desc) { 31762306a36Sopenharmony_ci case STI_BACK: 31862306a36Sopenharmony_ci return GAM_CTL_BACK_MASK; 31962306a36Sopenharmony_ci case STI_GDP_0: 32062306a36Sopenharmony_ci return GAM_CTL_GDP0_MASK; 32162306a36Sopenharmony_ci case STI_GDP_1: 32262306a36Sopenharmony_ci return GAM_CTL_GDP1_MASK; 32362306a36Sopenharmony_ci case STI_GDP_2: 32462306a36Sopenharmony_ci return GAM_CTL_GDP2_MASK; 32562306a36Sopenharmony_ci case STI_GDP_3: 32662306a36Sopenharmony_ci return GAM_CTL_GDP3_MASK; 32762306a36Sopenharmony_ci case STI_HQVDP_0: 32862306a36Sopenharmony_ci return GAM_CTL_VID0_MASK; 32962306a36Sopenharmony_ci case STI_CURSOR: 33062306a36Sopenharmony_ci return GAM_CTL_CURSOR_MASK; 33162306a36Sopenharmony_ci default: 33262306a36Sopenharmony_ci return 0; 33362306a36Sopenharmony_ci } 33462306a36Sopenharmony_ci} 33562306a36Sopenharmony_ci 33662306a36Sopenharmony_ciint sti_mixer_set_plane_status(struct sti_mixer *mixer, 33762306a36Sopenharmony_ci struct sti_plane *plane, bool status) 33862306a36Sopenharmony_ci{ 33962306a36Sopenharmony_ci u32 mask, val; 34062306a36Sopenharmony_ci 34162306a36Sopenharmony_ci DRM_DEBUG_DRIVER("%s %s %s\n", status ? "enable" : "disable", 34262306a36Sopenharmony_ci sti_mixer_to_str(mixer), sti_plane_to_str(plane)); 34362306a36Sopenharmony_ci 34462306a36Sopenharmony_ci mask = sti_mixer_get_plane_mask(plane); 34562306a36Sopenharmony_ci if (!mask) { 34662306a36Sopenharmony_ci DRM_ERROR("Can't find layer mask\n"); 34762306a36Sopenharmony_ci return -EINVAL; 34862306a36Sopenharmony_ci } 34962306a36Sopenharmony_ci 35062306a36Sopenharmony_ci val = sti_mixer_reg_read(mixer, GAM_MIXER_CTL); 35162306a36Sopenharmony_ci val &= ~mask; 35262306a36Sopenharmony_ci val |= status ? mask : 0; 35362306a36Sopenharmony_ci sti_mixer_reg_write(mixer, GAM_MIXER_CTL, val); 35462306a36Sopenharmony_ci 35562306a36Sopenharmony_ci return 0; 35662306a36Sopenharmony_ci} 35762306a36Sopenharmony_ci 35862306a36Sopenharmony_cistruct sti_mixer *sti_mixer_create(struct device *dev, 35962306a36Sopenharmony_ci struct drm_device *drm_dev, 36062306a36Sopenharmony_ci int id, 36162306a36Sopenharmony_ci void __iomem *baseaddr) 36262306a36Sopenharmony_ci{ 36362306a36Sopenharmony_ci struct sti_mixer *mixer = devm_kzalloc(dev, sizeof(*mixer), GFP_KERNEL); 36462306a36Sopenharmony_ci 36562306a36Sopenharmony_ci dev_dbg(dev, "%s\n", __func__); 36662306a36Sopenharmony_ci if (!mixer) { 36762306a36Sopenharmony_ci DRM_ERROR("Failed to allocated memory for mixer\n"); 36862306a36Sopenharmony_ci return NULL; 36962306a36Sopenharmony_ci } 37062306a36Sopenharmony_ci mixer->regs = baseaddr; 37162306a36Sopenharmony_ci mixer->dev = dev; 37262306a36Sopenharmony_ci mixer->id = id; 37362306a36Sopenharmony_ci 37462306a36Sopenharmony_ci DRM_DEBUG_DRIVER("%s created. Regs=%p\n", 37562306a36Sopenharmony_ci sti_mixer_to_str(mixer), mixer->regs); 37662306a36Sopenharmony_ci 37762306a36Sopenharmony_ci return mixer; 37862306a36Sopenharmony_ci} 379