linux/drivers/gpu/drm/imx/dcss/dcss-ss.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2/*
   3 * Copyright 2019 NXP.
   4 */
   5
   6#include <linux/device.h>
   7#include <linux/slab.h>
   8
   9#include "dcss-dev.h"
  10
  11#define DCSS_SS_SYS_CTRL                        0x00
  12#define   RUN_EN                                BIT(0)
  13#define DCSS_SS_DISPLAY                         0x10
  14#define   LRC_X_POS                             0
  15#define   LRC_X_MASK                            GENMASK(12, 0)
  16#define   LRC_Y_POS                             16
  17#define   LRC_Y_MASK                            GENMASK(28, 16)
  18#define DCSS_SS_HSYNC                           0x20
  19#define DCSS_SS_VSYNC                           0x30
  20#define   SYNC_START_POS                        0
  21#define   SYNC_START_MASK                       GENMASK(12, 0)
  22#define   SYNC_END_POS                          16
  23#define   SYNC_END_MASK                         GENMASK(28, 16)
  24#define   SYNC_POL                              BIT(31)
  25#define DCSS_SS_DE_ULC                          0x40
  26#define   ULC_X_POS                             0
  27#define   ULC_X_MASK                            GENMASK(12, 0)
  28#define   ULC_Y_POS                             16
  29#define   ULC_Y_MASK                            GENMASK(28, 16)
  30#define   ULC_POL                               BIT(31)
  31#define DCSS_SS_DE_LRC                          0x50
  32#define DCSS_SS_MODE                            0x60
  33#define   PIPE_MODE_POS                         0
  34#define   PIPE_MODE_MASK                        GENMASK(1, 0)
  35#define DCSS_SS_COEFF                           0x70
  36#define   HORIZ_A_POS                           0
  37#define   HORIZ_A_MASK                          GENMASK(3, 0)
  38#define   HORIZ_B_POS                           4
  39#define   HORIZ_B_MASK                          GENMASK(7, 4)
  40#define   HORIZ_C_POS                           8
  41#define   HORIZ_C_MASK                          GENMASK(11, 8)
  42#define   HORIZ_H_NORM_POS                      12
  43#define   HORIZ_H_NORM_MASK                     GENMASK(14, 12)
  44#define   VERT_A_POS                            16
  45#define   VERT_A_MASK                           GENMASK(19, 16)
  46#define   VERT_B_POS                            20
  47#define   VERT_B_MASK                           GENMASK(23, 20)
  48#define   VERT_C_POS                            24
  49#define   VERT_C_MASK                           GENMASK(27, 24)
  50#define   VERT_H_NORM_POS                       28
  51#define   VERT_H_NORM_MASK                      GENMASK(30, 28)
  52#define DCSS_SS_CLIP_CB                         0x80
  53#define DCSS_SS_CLIP_CR                         0x90
  54#define   CLIP_MIN_POS                          0
  55#define   CLIP_MIN_MASK                         GENMASK(9, 0)
  56#define   CLIP_MAX_POS                          0
  57#define   CLIP_MAX_MASK                         GENMASK(23, 16)
  58#define DCSS_SS_INTER_MODE                      0xA0
  59#define   INT_EN                                BIT(0)
  60#define   VSYNC_SHIFT                           BIT(1)
  61
  62struct dcss_ss {
  63        struct device *dev;
  64        void __iomem *base_reg;
  65        u32 base_ofs;
  66
  67        struct dcss_ctxld *ctxld;
  68        u32 ctx_id;
  69
  70        bool in_use;
  71};
  72
  73static void dcss_ss_write(struct dcss_ss *ss, u32 val, u32 ofs)
  74{
  75        if (!ss->in_use)
  76                dcss_writel(val, ss->base_reg + ofs);
  77
  78        dcss_ctxld_write(ss->ctxld, ss->ctx_id, val,
  79                         ss->base_ofs + ofs);
  80}
  81
  82int dcss_ss_init(struct dcss_dev *dcss, unsigned long ss_base)
  83{
  84        struct dcss_ss *ss;
  85
  86        ss = kzalloc(sizeof(*ss), GFP_KERNEL);
  87        if (!ss)
  88                return -ENOMEM;
  89
  90        dcss->ss = ss;
  91        ss->dev = dcss->dev;
  92        ss->ctxld = dcss->ctxld;
  93
  94        ss->base_reg = ioremap(ss_base, SZ_4K);
  95        if (!ss->base_reg) {
  96                dev_err(dcss->dev, "ss: unable to remap ss base\n");
  97                kfree(ss);
  98                return -ENOMEM;
  99        }
 100
 101        ss->base_ofs = ss_base;
 102        ss->ctx_id = CTX_SB_HP;
 103
 104        return 0;
 105}
 106
 107void dcss_ss_exit(struct dcss_ss *ss)
 108{
 109        /* stop SS */
 110        dcss_writel(0, ss->base_reg + DCSS_SS_SYS_CTRL);
 111
 112        if (ss->base_reg)
 113                iounmap(ss->base_reg);
 114
 115        kfree(ss);
 116}
 117
 118void dcss_ss_subsam_set(struct dcss_ss *ss)
 119{
 120        dcss_ss_write(ss, 0x41614161, DCSS_SS_COEFF);
 121        dcss_ss_write(ss, 0, DCSS_SS_MODE);
 122        dcss_ss_write(ss, 0x03ff0000, DCSS_SS_CLIP_CB);
 123        dcss_ss_write(ss, 0x03ff0000, DCSS_SS_CLIP_CR);
 124}
 125
 126void dcss_ss_sync_set(struct dcss_ss *ss, struct videomode *vm,
 127                      bool phsync, bool pvsync)
 128{
 129        u16 lrc_x, lrc_y;
 130        u16 hsync_start, hsync_end;
 131        u16 vsync_start, vsync_end;
 132        u16 de_ulc_x, de_ulc_y;
 133        u16 de_lrc_x, de_lrc_y;
 134
 135        lrc_x = vm->hfront_porch + vm->hback_porch + vm->hsync_len +
 136                vm->hactive - 1;
 137        lrc_y = vm->vfront_porch + vm->vback_porch + vm->vsync_len +
 138                vm->vactive - 1;
 139
 140        dcss_ss_write(ss, (lrc_y << LRC_Y_POS) | lrc_x, DCSS_SS_DISPLAY);
 141
 142        hsync_start = vm->hfront_porch + vm->hback_porch + vm->hsync_len +
 143                      vm->hactive - 1;
 144        hsync_end = vm->hsync_len - 1;
 145
 146        dcss_ss_write(ss, (phsync ? SYNC_POL : 0) |
 147                      ((u32)hsync_end << SYNC_END_POS) | hsync_start,
 148                      DCSS_SS_HSYNC);
 149
 150        vsync_start = vm->vfront_porch - 1;
 151        vsync_end = vm->vfront_porch + vm->vsync_len - 1;
 152
 153        dcss_ss_write(ss, (pvsync ? SYNC_POL : 0) |
 154                      ((u32)vsync_end << SYNC_END_POS) | vsync_start,
 155                      DCSS_SS_VSYNC);
 156
 157        de_ulc_x = vm->hsync_len + vm->hback_porch - 1;
 158        de_ulc_y = vm->vsync_len + vm->vfront_porch + vm->vback_porch;
 159
 160        dcss_ss_write(ss, SYNC_POL | ((u32)de_ulc_y << ULC_Y_POS) | de_ulc_x,
 161                      DCSS_SS_DE_ULC);
 162
 163        de_lrc_x = vm->hsync_len + vm->hback_porch + vm->hactive - 1;
 164        de_lrc_y = vm->vsync_len + vm->vfront_porch + vm->vback_porch +
 165                   vm->vactive - 1;
 166
 167        dcss_ss_write(ss, (de_lrc_y << LRC_Y_POS) | de_lrc_x, DCSS_SS_DE_LRC);
 168}
 169
 170void dcss_ss_enable(struct dcss_ss *ss)
 171{
 172        dcss_ss_write(ss, RUN_EN, DCSS_SS_SYS_CTRL);
 173        ss->in_use = true;
 174}
 175
 176void dcss_ss_shutoff(struct dcss_ss *ss)
 177{
 178        dcss_writel(0, ss->base_reg + DCSS_SS_SYS_CTRL);
 179        ss->in_use = false;
 180}
 181