Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  * Copyright (C) STMicroelectronics SA 2014
0004  * Authors: Benjamin Gaignard <benjamin.gaignard@st.com>
0005  *          Fabien Dessenne <fabien.dessenne@st.com>
0006  *          for STMicroelectronics.
0007  */
0008 
0009 #include <linux/moduleparam.h>
0010 #include <linux/seq_file.h>
0011 
0012 #include <drm/drm_print.h>
0013 
0014 #include "sti_compositor.h"
0015 #include "sti_mixer.h"
0016 #include "sti_vtg.h"
0017 
0018 /* Module parameter to set the background color of the mixer */
0019 static unsigned int bkg_color = 0x000000;
0020 MODULE_PARM_DESC(bkgcolor, "Value of the background color 0xRRGGBB");
0021 module_param_named(bkgcolor, bkg_color, int, 0644);
0022 
0023 /* regs offset */
0024 #define GAM_MIXER_CTL      0x00
0025 #define GAM_MIXER_BKC      0x04
0026 #define GAM_MIXER_BCO      0x0C
0027 #define GAM_MIXER_BCS      0x10
0028 #define GAM_MIXER_AVO      0x28
0029 #define GAM_MIXER_AVS      0x2C
0030 #define GAM_MIXER_CRB      0x34
0031 #define GAM_MIXER_ACT      0x38
0032 #define GAM_MIXER_MBP      0x3C
0033 #define GAM_MIXER_MX0      0x80
0034 
0035 /* id for depth of CRB reg */
0036 #define GAM_DEPTH_VID0_ID  1
0037 #define GAM_DEPTH_VID1_ID  2
0038 #define GAM_DEPTH_GDP0_ID  3
0039 #define GAM_DEPTH_GDP1_ID  4
0040 #define GAM_DEPTH_GDP2_ID  5
0041 #define GAM_DEPTH_GDP3_ID  6
0042 #define GAM_DEPTH_MASK_ID  7
0043 
0044 /* mask in CTL reg */
0045 #define GAM_CTL_BACK_MASK  BIT(0)
0046 #define GAM_CTL_VID0_MASK  BIT(1)
0047 #define GAM_CTL_VID1_MASK  BIT(2)
0048 #define GAM_CTL_GDP0_MASK  BIT(3)
0049 #define GAM_CTL_GDP1_MASK  BIT(4)
0050 #define GAM_CTL_GDP2_MASK  BIT(5)
0051 #define GAM_CTL_GDP3_MASK  BIT(6)
0052 #define GAM_CTL_CURSOR_MASK BIT(9)
0053 
0054 const char *sti_mixer_to_str(struct sti_mixer *mixer)
0055 {
0056     switch (mixer->id) {
0057     case STI_MIXER_MAIN:
0058         return "MAIN_MIXER";
0059     case STI_MIXER_AUX:
0060         return "AUX_MIXER";
0061     default:
0062         return "<UNKNOWN MIXER>";
0063     }
0064 }
0065 
0066 static inline u32 sti_mixer_reg_read(struct sti_mixer *mixer, u32 reg_id)
0067 {
0068     return readl(mixer->regs + reg_id);
0069 }
0070 
0071 static inline void sti_mixer_reg_write(struct sti_mixer *mixer,
0072                        u32 reg_id, u32 val)
0073 {
0074     writel(val, mixer->regs + reg_id);
0075 }
0076 
0077 #define DBGFS_DUMP(reg) seq_printf(s, "\n  %-25s 0x%08X", #reg, \
0078                    sti_mixer_reg_read(mixer, reg))
0079 
0080 static void mixer_dbg_ctl(struct seq_file *s, int val)
0081 {
0082     unsigned int i;
0083     int count = 0;
0084     char *const disp_layer[] = {"BKG", "VID0", "VID1", "GDP0",
0085                     "GDP1", "GDP2", "GDP3"};
0086 
0087     seq_puts(s, "\tEnabled: ");
0088     for (i = 0; i < 7; i++) {
0089         if (val & 1) {
0090             seq_printf(s, "%s ", disp_layer[i]);
0091             count++;
0092         }
0093         val = val >> 1;
0094     }
0095 
0096     val = val >> 2;
0097     if (val & 1) {
0098         seq_puts(s, "CURS ");
0099         count++;
0100     }
0101     if (!count)
0102         seq_puts(s, "Nothing");
0103 }
0104 
0105 static void mixer_dbg_crb(struct seq_file *s, int val)
0106 {
0107     int i;
0108 
0109     seq_puts(s, "\tDepth: ");
0110     for (i = 0; i < GAM_MIXER_NB_DEPTH_LEVEL; i++) {
0111         switch (val & GAM_DEPTH_MASK_ID) {
0112         case GAM_DEPTH_VID0_ID:
0113             seq_puts(s, "VID0");
0114             break;
0115         case GAM_DEPTH_VID1_ID:
0116             seq_puts(s, "VID1");
0117             break;
0118         case GAM_DEPTH_GDP0_ID:
0119             seq_puts(s, "GDP0");
0120             break;
0121         case GAM_DEPTH_GDP1_ID:
0122             seq_puts(s, "GDP1");
0123             break;
0124         case GAM_DEPTH_GDP2_ID:
0125             seq_puts(s, "GDP2");
0126             break;
0127         case GAM_DEPTH_GDP3_ID:
0128             seq_puts(s, "GDP3");
0129             break;
0130         default:
0131             seq_puts(s, "---");
0132         }
0133 
0134         if (i < GAM_MIXER_NB_DEPTH_LEVEL - 1)
0135             seq_puts(s, " < ");
0136         val = val >> 3;
0137     }
0138 }
0139 
0140 static void mixer_dbg_mxn(struct seq_file *s, void *addr)
0141 {
0142     int i;
0143 
0144     for (i = 1; i < 8; i++)
0145         seq_printf(s, "-0x%08X", (int)readl(addr + i * 4));
0146 }
0147 
0148 static int mixer_dbg_show(struct seq_file *s, void *arg)
0149 {
0150     struct drm_info_node *node = s->private;
0151     struct sti_mixer *mixer = (struct sti_mixer *)node->info_ent->data;
0152 
0153     seq_printf(s, "%s: (vaddr = 0x%p)",
0154            sti_mixer_to_str(mixer), mixer->regs);
0155 
0156     DBGFS_DUMP(GAM_MIXER_CTL);
0157     mixer_dbg_ctl(s, sti_mixer_reg_read(mixer, GAM_MIXER_CTL));
0158     DBGFS_DUMP(GAM_MIXER_BKC);
0159     DBGFS_DUMP(GAM_MIXER_BCO);
0160     DBGFS_DUMP(GAM_MIXER_BCS);
0161     DBGFS_DUMP(GAM_MIXER_AVO);
0162     DBGFS_DUMP(GAM_MIXER_AVS);
0163     DBGFS_DUMP(GAM_MIXER_CRB);
0164     mixer_dbg_crb(s, sti_mixer_reg_read(mixer, GAM_MIXER_CRB));
0165     DBGFS_DUMP(GAM_MIXER_ACT);
0166     DBGFS_DUMP(GAM_MIXER_MBP);
0167     DBGFS_DUMP(GAM_MIXER_MX0);
0168     mixer_dbg_mxn(s, mixer->regs + GAM_MIXER_MX0);
0169     seq_putc(s, '\n');
0170     return 0;
0171 }
0172 
0173 static struct drm_info_list mixer0_debugfs_files[] = {
0174     { "mixer_main", mixer_dbg_show, 0, NULL },
0175 };
0176 
0177 static struct drm_info_list mixer1_debugfs_files[] = {
0178     { "mixer_aux", mixer_dbg_show, 0, NULL },
0179 };
0180 
0181 void sti_mixer_debugfs_init(struct sti_mixer *mixer, struct drm_minor *minor)
0182 {
0183     unsigned int i;
0184     struct drm_info_list *mixer_debugfs_files;
0185     int nb_files;
0186 
0187     switch (mixer->id) {
0188     case STI_MIXER_MAIN:
0189         mixer_debugfs_files = mixer0_debugfs_files;
0190         nb_files = ARRAY_SIZE(mixer0_debugfs_files);
0191         break;
0192     case STI_MIXER_AUX:
0193         mixer_debugfs_files = mixer1_debugfs_files;
0194         nb_files = ARRAY_SIZE(mixer1_debugfs_files);
0195         break;
0196     default:
0197         return;
0198     }
0199 
0200     for (i = 0; i < nb_files; i++)
0201         mixer_debugfs_files[i].data = mixer;
0202 
0203     drm_debugfs_create_files(mixer_debugfs_files,
0204                  nb_files,
0205                  minor->debugfs_root, minor);
0206 }
0207 
0208 void sti_mixer_set_background_status(struct sti_mixer *mixer, bool enable)
0209 {
0210     u32 val = sti_mixer_reg_read(mixer, GAM_MIXER_CTL);
0211 
0212     val &= ~GAM_CTL_BACK_MASK;
0213     val |= enable;
0214     sti_mixer_reg_write(mixer, GAM_MIXER_CTL, val);
0215 }
0216 
0217 static void sti_mixer_set_background_color(struct sti_mixer *mixer,
0218                        unsigned int rgb)
0219 {
0220     sti_mixer_reg_write(mixer, GAM_MIXER_BKC, rgb);
0221 }
0222 
0223 static void sti_mixer_set_background_area(struct sti_mixer *mixer,
0224                       struct drm_display_mode *mode)
0225 {
0226     u32 ydo, xdo, yds, xds;
0227 
0228     ydo = sti_vtg_get_line_number(*mode, 0);
0229     yds = sti_vtg_get_line_number(*mode, mode->vdisplay - 1);
0230     xdo = sti_vtg_get_pixel_number(*mode, 0);
0231     xds = sti_vtg_get_pixel_number(*mode, mode->hdisplay - 1);
0232 
0233     sti_mixer_reg_write(mixer, GAM_MIXER_BCO, ydo << 16 | xdo);
0234     sti_mixer_reg_write(mixer, GAM_MIXER_BCS, yds << 16 | xds);
0235 }
0236 
0237 int sti_mixer_set_plane_depth(struct sti_mixer *mixer, struct sti_plane *plane)
0238 {
0239     int plane_id, depth = plane->drm_plane.state->normalized_zpos;
0240     unsigned int i;
0241     u32 mask, val;
0242 
0243     switch (plane->desc) {
0244     case STI_GDP_0:
0245         plane_id = GAM_DEPTH_GDP0_ID;
0246         break;
0247     case STI_GDP_1:
0248         plane_id = GAM_DEPTH_GDP1_ID;
0249         break;
0250     case STI_GDP_2:
0251         plane_id = GAM_DEPTH_GDP2_ID;
0252         break;
0253     case STI_GDP_3:
0254         plane_id = GAM_DEPTH_GDP3_ID;
0255         break;
0256     case STI_HQVDP_0:
0257         plane_id = GAM_DEPTH_VID0_ID;
0258         break;
0259     case STI_CURSOR:
0260         /* no need to set depth for cursor */
0261         return 0;
0262     default:
0263         DRM_ERROR("Unknown plane %d\n", plane->desc);
0264         return 1;
0265     }
0266 
0267     /* Search if a previous depth was already assigned to the plane */
0268     val = sti_mixer_reg_read(mixer, GAM_MIXER_CRB);
0269     for (i = 0; i < GAM_MIXER_NB_DEPTH_LEVEL; i++) {
0270         mask = GAM_DEPTH_MASK_ID << (3 * i);
0271         if ((val & mask) == plane_id << (3 * i))
0272             break;
0273     }
0274 
0275     mask |= GAM_DEPTH_MASK_ID << (3 * depth);
0276     plane_id = plane_id << (3 * depth);
0277 
0278     DRM_DEBUG_DRIVER("%s %s depth=%d\n", sti_mixer_to_str(mixer),
0279              sti_plane_to_str(plane), depth);
0280     dev_dbg(mixer->dev, "GAM_MIXER_CRB val 0x%x mask 0x%x\n",
0281         plane_id, mask);
0282 
0283     val &= ~mask;
0284     val |= plane_id;
0285     sti_mixer_reg_write(mixer, GAM_MIXER_CRB, val);
0286 
0287     dev_dbg(mixer->dev, "Read GAM_MIXER_CRB 0x%x\n",
0288         sti_mixer_reg_read(mixer, GAM_MIXER_CRB));
0289     return 0;
0290 }
0291 
0292 int sti_mixer_active_video_area(struct sti_mixer *mixer,
0293                 struct drm_display_mode *mode)
0294 {
0295     u32 ydo, xdo, yds, xds;
0296 
0297     ydo = sti_vtg_get_line_number(*mode, 0);
0298     yds = sti_vtg_get_line_number(*mode, mode->vdisplay - 1);
0299     xdo = sti_vtg_get_pixel_number(*mode, 0);
0300     xds = sti_vtg_get_pixel_number(*mode, mode->hdisplay - 1);
0301 
0302     DRM_DEBUG_DRIVER("%s active video area xdo:%d ydo:%d xds:%d yds:%d\n",
0303              sti_mixer_to_str(mixer), xdo, ydo, xds, yds);
0304     sti_mixer_reg_write(mixer, GAM_MIXER_AVO, ydo << 16 | xdo);
0305     sti_mixer_reg_write(mixer, GAM_MIXER_AVS, yds << 16 | xds);
0306 
0307     sti_mixer_set_background_color(mixer, bkg_color);
0308 
0309     sti_mixer_set_background_area(mixer, mode);
0310     sti_mixer_set_background_status(mixer, true);
0311     return 0;
0312 }
0313 
0314 static u32 sti_mixer_get_plane_mask(struct sti_plane *plane)
0315 {
0316     switch (plane->desc) {
0317     case STI_BACK:
0318         return GAM_CTL_BACK_MASK;
0319     case STI_GDP_0:
0320         return GAM_CTL_GDP0_MASK;
0321     case STI_GDP_1:
0322         return GAM_CTL_GDP1_MASK;
0323     case STI_GDP_2:
0324         return GAM_CTL_GDP2_MASK;
0325     case STI_GDP_3:
0326         return GAM_CTL_GDP3_MASK;
0327     case STI_HQVDP_0:
0328         return GAM_CTL_VID0_MASK;
0329     case STI_CURSOR:
0330         return GAM_CTL_CURSOR_MASK;
0331     default:
0332         return 0;
0333     }
0334 }
0335 
0336 int sti_mixer_set_plane_status(struct sti_mixer *mixer,
0337                    struct sti_plane *plane, bool status)
0338 {
0339     u32 mask, val;
0340 
0341     DRM_DEBUG_DRIVER("%s %s %s\n", status ? "enable" : "disable",
0342              sti_mixer_to_str(mixer), sti_plane_to_str(plane));
0343 
0344     mask = sti_mixer_get_plane_mask(plane);
0345     if (!mask) {
0346         DRM_ERROR("Can't find layer mask\n");
0347         return -EINVAL;
0348     }
0349 
0350     val = sti_mixer_reg_read(mixer, GAM_MIXER_CTL);
0351     val &= ~mask;
0352     val |= status ? mask : 0;
0353     sti_mixer_reg_write(mixer, GAM_MIXER_CTL, val);
0354 
0355     return 0;
0356 }
0357 
0358 struct sti_mixer *sti_mixer_create(struct device *dev,
0359                    struct drm_device *drm_dev,
0360                    int id,
0361                    void __iomem *baseaddr)
0362 {
0363     struct sti_mixer *mixer = devm_kzalloc(dev, sizeof(*mixer), GFP_KERNEL);
0364 
0365     dev_dbg(dev, "%s\n", __func__);
0366     if (!mixer) {
0367         DRM_ERROR("Failed to allocated memory for mixer\n");
0368         return NULL;
0369     }
0370     mixer->regs = baseaddr;
0371     mixer->dev = dev;
0372     mixer->id = id;
0373 
0374     DRM_DEBUG_DRIVER("%s created. Regs=%p\n",
0375              sti_mixer_to_str(mixer), mixer->regs);
0376 
0377     return mixer;
0378 }