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