linux/drivers/gpu/drm/sti/sti_cursor.c
<<
>>
Prefs
   1/*
   2 * Copyright (C) STMicroelectronics SA 2014
   3 * Authors: Vincent Abriou <vincent.abriou@st.com>
   4 *          Fabien Dessenne <fabien.dessenne@st.com>
   5 *          for STMicroelectronics.
   6 * License terms:  GNU General Public License (GPL), version 2
   7 */
   8#include <drm/drmP.h>
   9
  10#include "sti_cursor.h"
  11#include "sti_layer.h"
  12#include "sti_vtg.h"
  13
  14/* Registers */
  15#define CUR_CTL             0x00
  16#define CUR_VPO             0x0C
  17#define CUR_PML             0x14
  18#define CUR_PMP             0x18
  19#define CUR_SIZE            0x1C
  20#define CUR_CML             0x20
  21#define CUR_AWS             0x28
  22#define CUR_AWE             0x2C
  23
  24#define CUR_CTL_CLUT_UPDATE BIT(1)
  25
  26#define STI_CURS_MIN_SIZE   1
  27#define STI_CURS_MAX_SIZE   128
  28
  29/*
  30 * pixmap dma buffer stucture
  31 *
  32 * @paddr:  physical address
  33 * @size:   buffer size
  34 * @base:   virtual address
  35 */
  36struct dma_pixmap {
  37        dma_addr_t paddr;
  38        size_t size;
  39        void *base;
  40};
  41
  42/**
  43 * STI Cursor structure
  44 *
  45 * @layer:      layer structure
  46 * @width:      cursor width
  47 * @height:     cursor height
  48 * @clut:       color look up table
  49 * @clut_paddr: color look up table physical address
  50 * @pixmap:     pixmap dma buffer (clut8-format cursor)
  51 */
  52struct sti_cursor {
  53        struct sti_layer layer;
  54        unsigned int width;
  55        unsigned int height;
  56        unsigned short *clut;
  57        dma_addr_t clut_paddr;
  58        struct dma_pixmap pixmap;
  59};
  60
  61static const uint32_t cursor_supported_formats[] = {
  62        DRM_FORMAT_ARGB8888,
  63};
  64
  65#define to_sti_cursor(x) container_of(x, struct sti_cursor, layer)
  66
  67static const uint32_t *sti_cursor_get_formats(struct sti_layer *layer)
  68{
  69        return cursor_supported_formats;
  70}
  71
  72static unsigned int sti_cursor_get_nb_formats(struct sti_layer *layer)
  73{
  74        return ARRAY_SIZE(cursor_supported_formats);
  75}
  76
  77static void sti_cursor_argb8888_to_clut8(struct sti_layer *layer)
  78{
  79        struct sti_cursor *cursor = to_sti_cursor(layer);
  80        u32 *src = layer->vaddr;
  81        u8  *dst = cursor->pixmap.base;
  82        unsigned int i, j;
  83        u32 a, r, g, b;
  84
  85        for (i = 0; i < cursor->height; i++) {
  86                for (j = 0; j < cursor->width; j++) {
  87                        /* Pick the 2 higher bits of each component */
  88                        a = (*src >> 30) & 3;
  89                        r = (*src >> 22) & 3;
  90                        g = (*src >> 14) & 3;
  91                        b = (*src >> 6) & 3;
  92                        *dst = a << 6 | r << 4 | g << 2 | b;
  93                        src++;
  94                        dst++;
  95                }
  96        }
  97}
  98
  99static int sti_cursor_prepare_layer(struct sti_layer *layer, bool first_prepare)
 100{
 101        struct sti_cursor *cursor = to_sti_cursor(layer);
 102        struct drm_display_mode *mode = layer->mode;
 103        u32 y, x;
 104        u32 val;
 105
 106        DRM_DEBUG_DRIVER("\n");
 107
 108        dev_dbg(layer->dev, "%s %s\n", __func__, sti_layer_to_str(layer));
 109
 110        if (layer->src_w < STI_CURS_MIN_SIZE ||
 111            layer->src_h < STI_CURS_MIN_SIZE ||
 112            layer->src_w > STI_CURS_MAX_SIZE ||
 113            layer->src_h > STI_CURS_MAX_SIZE) {
 114                DRM_ERROR("Invalid cursor size (%dx%d)\n",
 115                                layer->src_w, layer->src_h);
 116                return -EINVAL;
 117        }
 118
 119        /* If the cursor size has changed, re-allocated the pixmap */
 120        if (!cursor->pixmap.base ||
 121            (cursor->width != layer->src_w) ||
 122            (cursor->height != layer->src_h)) {
 123                cursor->width = layer->src_w;
 124                cursor->height = layer->src_h;
 125
 126                if (cursor->pixmap.base)
 127                        dma_free_writecombine(layer->dev,
 128                                              cursor->pixmap.size,
 129                                              cursor->pixmap.base,
 130                                              cursor->pixmap.paddr);
 131
 132                cursor->pixmap.size = cursor->width * cursor->height;
 133
 134                cursor->pixmap.base = dma_alloc_writecombine(layer->dev,
 135                                                        cursor->pixmap.size,
 136                                                        &cursor->pixmap.paddr,
 137                                                        GFP_KERNEL | GFP_DMA);
 138                if (!cursor->pixmap.base) {
 139                        DRM_ERROR("Failed to allocate memory for pixmap\n");
 140                        return -ENOMEM;
 141                }
 142        }
 143
 144        /* Convert ARGB8888 to CLUT8 */
 145        sti_cursor_argb8888_to_clut8(layer);
 146
 147        /* AWS and AWE depend on the mode */
 148        y = sti_vtg_get_line_number(*mode, 0);
 149        x = sti_vtg_get_pixel_number(*mode, 0);
 150        val = y << 16 | x;
 151        writel(val, layer->regs + CUR_AWS);
 152        y = sti_vtg_get_line_number(*mode, mode->vdisplay - 1);
 153        x = sti_vtg_get_pixel_number(*mode, mode->hdisplay - 1);
 154        val = y << 16 | x;
 155        writel(val, layer->regs + CUR_AWE);
 156
 157        if (first_prepare) {
 158                /* Set and fetch CLUT */
 159                writel(cursor->clut_paddr, layer->regs + CUR_CML);
 160                writel(CUR_CTL_CLUT_UPDATE, layer->regs + CUR_CTL);
 161        }
 162
 163        return 0;
 164}
 165
 166static int sti_cursor_commit_layer(struct sti_layer *layer)
 167{
 168        struct sti_cursor *cursor = to_sti_cursor(layer);
 169        struct drm_display_mode *mode = layer->mode;
 170        u32 ydo, xdo;
 171
 172        dev_dbg(layer->dev, "%s %s\n", __func__, sti_layer_to_str(layer));
 173
 174        /* Set memory location, size, and position */
 175        writel(cursor->pixmap.paddr, layer->regs + CUR_PML);
 176        writel(cursor->width, layer->regs + CUR_PMP);
 177        writel(cursor->height << 16 | cursor->width, layer->regs + CUR_SIZE);
 178
 179        ydo = sti_vtg_get_line_number(*mode, layer->dst_y);
 180        xdo = sti_vtg_get_pixel_number(*mode, layer->dst_y);
 181        writel((ydo << 16) | xdo, layer->regs + CUR_VPO);
 182
 183        return 0;
 184}
 185
 186static int sti_cursor_disable_layer(struct sti_layer *layer)
 187{
 188        return 0;
 189}
 190
 191static void sti_cursor_init(struct sti_layer *layer)
 192{
 193        struct sti_cursor *cursor = to_sti_cursor(layer);
 194        unsigned short *base = cursor->clut;
 195        unsigned int a, r, g, b;
 196
 197        /* Assign CLUT values, ARGB444 format */
 198        for (a = 0; a < 4; a++)
 199                for (r = 0; r < 4; r++)
 200                        for (g = 0; g < 4; g++)
 201                                for (b = 0; b < 4; b++)
 202                                        *base++ = (a * 5) << 12 |
 203                                                  (r * 5) << 8 |
 204                                                  (g * 5) << 4 |
 205                                                  (b * 5);
 206}
 207
 208static const struct sti_layer_funcs cursor_ops = {
 209        .get_formats = sti_cursor_get_formats,
 210        .get_nb_formats = sti_cursor_get_nb_formats,
 211        .init = sti_cursor_init,
 212        .prepare = sti_cursor_prepare_layer,
 213        .commit = sti_cursor_commit_layer,
 214        .disable = sti_cursor_disable_layer,
 215};
 216
 217struct sti_layer *sti_cursor_create(struct device *dev)
 218{
 219        struct sti_cursor *cursor;
 220
 221        cursor = devm_kzalloc(dev, sizeof(*cursor), GFP_KERNEL);
 222        if (!cursor) {
 223                DRM_ERROR("Failed to allocate memory for cursor\n");
 224                return NULL;
 225        }
 226
 227        /* Allocate clut buffer */
 228        cursor->clut = dma_alloc_writecombine(dev,
 229                        0x100 * sizeof(unsigned short),
 230                        &cursor->clut_paddr,
 231                        GFP_KERNEL | GFP_DMA);
 232
 233        if (!cursor->clut) {
 234                DRM_ERROR("Failed to allocate memory for cursor clut\n");
 235                devm_kfree(dev, cursor);
 236                return NULL;
 237        }
 238
 239        cursor->layer.ops = &cursor_ops;
 240
 241        return (struct sti_layer *)cursor;
 242}
 243