root/drivers/gpu/drm/sti/sti_mixer.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. sti_mixer_to_str
  2. sti_mixer_reg_read
  3. sti_mixer_reg_write
  4. mixer_dbg_ctl
  5. mixer_dbg_crb
  6. mixer_dbg_mxn
  7. mixer_dbg_show
  8. sti_mixer_debugfs_init
  9. sti_mixer_set_background_status
  10. sti_mixer_set_background_color
  11. sti_mixer_set_background_area
  12. sti_mixer_set_plane_depth
  13. sti_mixer_active_video_area
  14. sti_mixer_get_plane_mask
  15. sti_mixer_set_plane_status
  16. sti_mixer_create

   1 // SPDX-License-Identifier: GPL-2.0
   2 /*
   3  * Copyright (C) STMicroelectronics SA 2014
   4  * Authors: Benjamin Gaignard <benjamin.gaignard@st.com>
   5  *          Fabien Dessenne <fabien.dessenne@st.com>
   6  *          for STMicroelectronics.
   7  */
   8 
   9 #include <linux/moduleparam.h>
  10 #include <linux/seq_file.h>
  11 
  12 #include <drm/drm_print.h>
  13 
  14 #include "sti_compositor.h"
  15 #include "sti_mixer.h"
  16 #include "sti_vtg.h"
  17 
  18 /* Module parameter to set the background color of the mixer */
  19 static unsigned int bkg_color = 0x000000;
  20 MODULE_PARM_DESC(bkgcolor, "Value of the background color 0xRRGGBB");
  21 module_param_named(bkgcolor, bkg_color, int, 0644);
  22 
  23 /* regs offset */
  24 #define GAM_MIXER_CTL      0x00
  25 #define GAM_MIXER_BKC      0x04
  26 #define GAM_MIXER_BCO      0x0C
  27 #define GAM_MIXER_BCS      0x10
  28 #define GAM_MIXER_AVO      0x28
  29 #define GAM_MIXER_AVS      0x2C
  30 #define GAM_MIXER_CRB      0x34
  31 #define GAM_MIXER_ACT      0x38
  32 #define GAM_MIXER_MBP      0x3C
  33 #define GAM_MIXER_MX0      0x80
  34 
  35 /* id for depth of CRB reg */
  36 #define GAM_DEPTH_VID0_ID  1
  37 #define GAM_DEPTH_VID1_ID  2
  38 #define GAM_DEPTH_GDP0_ID  3
  39 #define GAM_DEPTH_GDP1_ID  4
  40 #define GAM_DEPTH_GDP2_ID  5
  41 #define GAM_DEPTH_GDP3_ID  6
  42 #define GAM_DEPTH_MASK_ID  7
  43 
  44 /* mask in CTL reg */
  45 #define GAM_CTL_BACK_MASK  BIT(0)
  46 #define GAM_CTL_VID0_MASK  BIT(1)
  47 #define GAM_CTL_VID1_MASK  BIT(2)
  48 #define GAM_CTL_GDP0_MASK  BIT(3)
  49 #define GAM_CTL_GDP1_MASK  BIT(4)
  50 #define GAM_CTL_GDP2_MASK  BIT(5)
  51 #define GAM_CTL_GDP3_MASK  BIT(6)
  52 #define GAM_CTL_CURSOR_MASK BIT(9)
  53 
  54 const char *sti_mixer_to_str(struct sti_mixer *mixer)
  55 {
  56         switch (mixer->id) {
  57         case STI_MIXER_MAIN:
  58                 return "MAIN_MIXER";
  59         case STI_MIXER_AUX:
  60                 return "AUX_MIXER";
  61         default:
  62                 return "<UNKNOWN MIXER>";
  63         }
  64 }
  65 
  66 static inline u32 sti_mixer_reg_read(struct sti_mixer *mixer, u32 reg_id)
  67 {
  68         return readl(mixer->regs + reg_id);
  69 }
  70 
  71 static inline void sti_mixer_reg_write(struct sti_mixer *mixer,
  72                                        u32 reg_id, u32 val)
  73 {
  74         writel(val, mixer->regs + reg_id);
  75 }
  76 
  77 #define DBGFS_DUMP(reg) seq_printf(s, "\n  %-25s 0x%08X", #reg, \
  78                                    sti_mixer_reg_read(mixer, reg))
  79 
  80 static void mixer_dbg_ctl(struct seq_file *s, int val)
  81 {
  82         unsigned int i;
  83         int count = 0;
  84         char *const disp_layer[] = {"BKG", "VID0", "VID1", "GDP0",
  85                                     "GDP1", "GDP2", "GDP3"};
  86 
  87         seq_puts(s, "\tEnabled: ");
  88         for (i = 0; i < 7; i++) {
  89                 if (val & 1) {
  90                         seq_printf(s, "%s ", disp_layer[i]);
  91                         count++;
  92                 }
  93                 val = val >> 1;
  94         }
  95 
  96         val = val >> 2;
  97         if (val & 1) {
  98                 seq_puts(s, "CURS ");
  99                 count++;
 100         }
 101         if (!count)
 102                 seq_puts(s, "Nothing");
 103 }
 104 
 105 static void mixer_dbg_crb(struct seq_file *s, int val)
 106 {
 107         int i;
 108 
 109         seq_puts(s, "\tDepth: ");
 110         for (i = 0; i < GAM_MIXER_NB_DEPTH_LEVEL; i++) {
 111                 switch (val & GAM_DEPTH_MASK_ID) {
 112                 case GAM_DEPTH_VID0_ID:
 113                         seq_puts(s, "VID0");
 114                         break;
 115                 case GAM_DEPTH_VID1_ID:
 116                         seq_puts(s, "VID1");
 117                         break;
 118                 case GAM_DEPTH_GDP0_ID:
 119                         seq_puts(s, "GDP0");
 120                         break;
 121                 case GAM_DEPTH_GDP1_ID:
 122                         seq_puts(s, "GDP1");
 123                         break;
 124                 case GAM_DEPTH_GDP2_ID:
 125                         seq_puts(s, "GDP2");
 126                         break;
 127                 case GAM_DEPTH_GDP3_ID:
 128                         seq_puts(s, "GDP3");
 129                         break;
 130                 default:
 131                         seq_puts(s, "---");
 132                 }
 133 
 134                 if (i < GAM_MIXER_NB_DEPTH_LEVEL - 1)
 135                         seq_puts(s, " < ");
 136                 val = val >> 3;
 137         }
 138 }
 139 
 140 static void mixer_dbg_mxn(struct seq_file *s, void *addr)
 141 {
 142         int i;
 143 
 144         for (i = 1; i < 8; i++)
 145                 seq_printf(s, "-0x%08X", (int)readl(addr + i * 4));
 146 }
 147 
 148 static int mixer_dbg_show(struct seq_file *s, void *arg)
 149 {
 150         struct drm_info_node *node = s->private;
 151         struct sti_mixer *mixer = (struct sti_mixer *)node->info_ent->data;
 152 
 153         seq_printf(s, "%s: (vaddr = 0x%p)",
 154                    sti_mixer_to_str(mixer), mixer->regs);
 155 
 156         DBGFS_DUMP(GAM_MIXER_CTL);
 157         mixer_dbg_ctl(s, sti_mixer_reg_read(mixer, GAM_MIXER_CTL));
 158         DBGFS_DUMP(GAM_MIXER_BKC);
 159         DBGFS_DUMP(GAM_MIXER_BCO);
 160         DBGFS_DUMP(GAM_MIXER_BCS);
 161         DBGFS_DUMP(GAM_MIXER_AVO);
 162         DBGFS_DUMP(GAM_MIXER_AVS);
 163         DBGFS_DUMP(GAM_MIXER_CRB);
 164         mixer_dbg_crb(s, sti_mixer_reg_read(mixer, GAM_MIXER_CRB));
 165         DBGFS_DUMP(GAM_MIXER_ACT);
 166         DBGFS_DUMP(GAM_MIXER_MBP);
 167         DBGFS_DUMP(GAM_MIXER_MX0);
 168         mixer_dbg_mxn(s, mixer->regs + GAM_MIXER_MX0);
 169         seq_putc(s, '\n');
 170         return 0;
 171 }
 172 
 173 static struct drm_info_list mixer0_debugfs_files[] = {
 174         { "mixer_main", mixer_dbg_show, 0, NULL },
 175 };
 176 
 177 static struct drm_info_list mixer1_debugfs_files[] = {
 178         { "mixer_aux", mixer_dbg_show, 0, NULL },
 179 };
 180 
 181 int sti_mixer_debugfs_init(struct sti_mixer *mixer, struct drm_minor *minor)
 182 {
 183         unsigned int i;
 184         struct drm_info_list *mixer_debugfs_files;
 185         int nb_files;
 186 
 187         switch (mixer->id) {
 188         case STI_MIXER_MAIN:
 189                 mixer_debugfs_files = mixer0_debugfs_files;
 190                 nb_files = ARRAY_SIZE(mixer0_debugfs_files);
 191                 break;
 192         case STI_MIXER_AUX:
 193                 mixer_debugfs_files = mixer1_debugfs_files;
 194                 nb_files = ARRAY_SIZE(mixer1_debugfs_files);
 195                 break;
 196         default:
 197                 return -EINVAL;
 198         }
 199 
 200         for (i = 0; i < nb_files; i++)
 201                 mixer_debugfs_files[i].data = mixer;
 202 
 203         return drm_debugfs_create_files(mixer_debugfs_files,
 204                                         nb_files,
 205                                         minor->debugfs_root, minor);
 206 }
 207 
 208 void sti_mixer_set_background_status(struct sti_mixer *mixer, bool enable)
 209 {
 210         u32 val = sti_mixer_reg_read(mixer, GAM_MIXER_CTL);
 211 
 212         val &= ~GAM_CTL_BACK_MASK;
 213         val |= enable;
 214         sti_mixer_reg_write(mixer, GAM_MIXER_CTL, val);
 215 }
 216 
 217 static void sti_mixer_set_background_color(struct sti_mixer *mixer,
 218                                            unsigned int rgb)
 219 {
 220         sti_mixer_reg_write(mixer, GAM_MIXER_BKC, rgb);
 221 }
 222 
 223 static void sti_mixer_set_background_area(struct sti_mixer *mixer,
 224                                           struct drm_display_mode *mode)
 225 {
 226         u32 ydo, xdo, yds, xds;
 227 
 228         ydo = sti_vtg_get_line_number(*mode, 0);
 229         yds = sti_vtg_get_line_number(*mode, mode->vdisplay - 1);
 230         xdo = sti_vtg_get_pixel_number(*mode, 0);
 231         xds = sti_vtg_get_pixel_number(*mode, mode->hdisplay - 1);
 232 
 233         sti_mixer_reg_write(mixer, GAM_MIXER_BCO, ydo << 16 | xdo);
 234         sti_mixer_reg_write(mixer, GAM_MIXER_BCS, yds << 16 | xds);
 235 }
 236 
 237 int sti_mixer_set_plane_depth(struct sti_mixer *mixer, struct sti_plane *plane)
 238 {
 239         int plane_id, depth = plane->drm_plane.state->normalized_zpos;
 240         unsigned int i;
 241         u32 mask, val;
 242 
 243         switch (plane->desc) {
 244         case STI_GDP_0:
 245                 plane_id = GAM_DEPTH_GDP0_ID;
 246                 break;
 247         case STI_GDP_1:
 248                 plane_id = GAM_DEPTH_GDP1_ID;
 249                 break;
 250         case STI_GDP_2:
 251                 plane_id = GAM_DEPTH_GDP2_ID;
 252                 break;
 253         case STI_GDP_3:
 254                 plane_id = GAM_DEPTH_GDP3_ID;
 255                 break;
 256         case STI_HQVDP_0:
 257                 plane_id = GAM_DEPTH_VID0_ID;
 258                 break;
 259         case STI_CURSOR:
 260                 /* no need to set depth for cursor */
 261                 return 0;
 262         default:
 263                 DRM_ERROR("Unknown plane %d\n", plane->desc);
 264                 return 1;
 265         }
 266 
 267         /* Search if a previous depth was already assigned to the plane */
 268         val = sti_mixer_reg_read(mixer, GAM_MIXER_CRB);
 269         for (i = 0; i < GAM_MIXER_NB_DEPTH_LEVEL; i++) {
 270                 mask = GAM_DEPTH_MASK_ID << (3 * i);
 271                 if ((val & mask) == plane_id << (3 * i))
 272                         break;
 273         }
 274 
 275         mask |= GAM_DEPTH_MASK_ID << (3 * depth);
 276         plane_id = plane_id << (3 * depth);
 277 
 278         DRM_DEBUG_DRIVER("%s %s depth=%d\n", sti_mixer_to_str(mixer),
 279                          sti_plane_to_str(plane), depth);
 280         dev_dbg(mixer->dev, "GAM_MIXER_CRB val 0x%x mask 0x%x\n",
 281                 plane_id, mask);
 282 
 283         val &= ~mask;
 284         val |= plane_id;
 285         sti_mixer_reg_write(mixer, GAM_MIXER_CRB, val);
 286 
 287         dev_dbg(mixer->dev, "Read GAM_MIXER_CRB 0x%x\n",
 288                 sti_mixer_reg_read(mixer, GAM_MIXER_CRB));
 289         return 0;
 290 }
 291 
 292 int sti_mixer_active_video_area(struct sti_mixer *mixer,
 293                                 struct drm_display_mode *mode)
 294 {
 295         u32 ydo, xdo, yds, xds;
 296 
 297         ydo = sti_vtg_get_line_number(*mode, 0);
 298         yds = sti_vtg_get_line_number(*mode, mode->vdisplay - 1);
 299         xdo = sti_vtg_get_pixel_number(*mode, 0);
 300         xds = sti_vtg_get_pixel_number(*mode, mode->hdisplay - 1);
 301 
 302         DRM_DEBUG_DRIVER("%s active video area xdo:%d ydo:%d xds:%d yds:%d\n",
 303                          sti_mixer_to_str(mixer), xdo, ydo, xds, yds);
 304         sti_mixer_reg_write(mixer, GAM_MIXER_AVO, ydo << 16 | xdo);
 305         sti_mixer_reg_write(mixer, GAM_MIXER_AVS, yds << 16 | xds);
 306 
 307         sti_mixer_set_background_color(mixer, bkg_color);
 308 
 309         sti_mixer_set_background_area(mixer, mode);
 310         sti_mixer_set_background_status(mixer, true);
 311         return 0;
 312 }
 313 
 314 static u32 sti_mixer_get_plane_mask(struct sti_plane *plane)
 315 {
 316         switch (plane->desc) {
 317         case STI_BACK:
 318                 return GAM_CTL_BACK_MASK;
 319         case STI_GDP_0:
 320                 return GAM_CTL_GDP0_MASK;
 321         case STI_GDP_1:
 322                 return GAM_CTL_GDP1_MASK;
 323         case STI_GDP_2:
 324                 return GAM_CTL_GDP2_MASK;
 325         case STI_GDP_3:
 326                 return GAM_CTL_GDP3_MASK;
 327         case STI_HQVDP_0:
 328                 return GAM_CTL_VID0_MASK;
 329         case STI_CURSOR:
 330                 return GAM_CTL_CURSOR_MASK;
 331         default:
 332                 return 0;
 333         }
 334 }
 335 
 336 int sti_mixer_set_plane_status(struct sti_mixer *mixer,
 337                                struct sti_plane *plane, bool status)
 338 {
 339         u32 mask, val;
 340 
 341         DRM_DEBUG_DRIVER("%s %s %s\n", status ? "enable" : "disable",
 342                          sti_mixer_to_str(mixer), sti_plane_to_str(plane));
 343 
 344         mask = sti_mixer_get_plane_mask(plane);
 345         if (!mask) {
 346                 DRM_ERROR("Can't find layer mask\n");
 347                 return -EINVAL;
 348         }
 349 
 350         val = sti_mixer_reg_read(mixer, GAM_MIXER_CTL);
 351         val &= ~mask;
 352         val |= status ? mask : 0;
 353         sti_mixer_reg_write(mixer, GAM_MIXER_CTL, val);
 354 
 355         return 0;
 356 }
 357 
 358 struct sti_mixer *sti_mixer_create(struct device *dev,
 359                                    struct drm_device *drm_dev,
 360                                    int id,
 361                                    void __iomem *baseaddr)
 362 {
 363         struct sti_mixer *mixer = devm_kzalloc(dev, sizeof(*mixer), GFP_KERNEL);
 364 
 365         dev_dbg(dev, "%s\n", __func__);
 366         if (!mixer) {
 367                 DRM_ERROR("Failed to allocated memory for mixer\n");
 368                 return NULL;
 369         }
 370         mixer->regs = baseaddr;
 371         mixer->dev = dev;
 372         mixer->id = id;
 373 
 374         DRM_DEBUG_DRIVER("%s created. Regs=%p\n",
 375                          sti_mixer_to_str(mixer), mixer->regs);
 376 
 377         return mixer;
 378 }

/* [<][>][^][v][top][bottom][index][help] */