linux/drivers/gpu/drm/xylon/xylon_logicvc.c
<<
>>
Prefs
   1/*
   2 * Xylon DRM driver logiCVC functions
   3 *
   4 * Copyright (C) 2014 Xylon d.o.o.
   5 * Author: Davor Joja <davor.joja@logicbricks.com>
   6 *
   7 * This software is licensed under the terms of the GNU General Public
   8 * License version 2, as published by the Free Software Foundation, and
   9 * may be copied, distributed, and modified under those terms.
  10 *
  11 * This program is distributed in the hope that it will be useful,
  12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14 * GNU General Public License for more details.
  15 */
  16
  17#include <drm/drmP.h>
  18
  19#include <linux/device.h>
  20#include <linux/err.h>
  21#include <linux/io.h>
  22#include <linux/module.h>
  23#include <linux/of_address.h>
  24#include <linux/of_device.h>
  25#include <linux/of_irq.h>
  26#include <linux/slab.h>
  27
  28#include <video/videomode.h>
  29
  30#include "xylon_drv.h"
  31#include "xylon_logicvc_helper.h"
  32#include "xylon_logicvc_hw.h"
  33#include "xylon_logicvc_layer.h"
  34
  35/*
  36 * All logiCVC registers are only 32-bit accessible.
  37 * All logiCVC registers are aligned to 8 byte boundary.
  38 */
  39#define LOGICVC_REG_STRIDE              8
  40#define LOGICVC_HSYNC_FRONT_PORCH_ROFF  (0  * LOGICVC_REG_STRIDE)
  41#define LOGICVC_HSYNC_ROFF              (1  * LOGICVC_REG_STRIDE)
  42#define LOGICVC_HSYNC_BACK_PORCH_ROFF   (2  * LOGICVC_REG_STRIDE)
  43#define LOGICVC_HRES_ROFF               (3  * LOGICVC_REG_STRIDE)
  44#define LOGICVC_VSYNC_FRONT_PORCH_ROFF  (4  * LOGICVC_REG_STRIDE)
  45#define LOGICVC_VSYNC_ROFF              (5  * LOGICVC_REG_STRIDE)
  46#define LOGICVC_VSYNC_BACK_PORCH_ROFF   (6  * LOGICVC_REG_STRIDE)
  47#define LOGICVC_VRES_ROFF               (7  * LOGICVC_REG_STRIDE)
  48#define LOGICVC_CTRL_ROFF               (8  * LOGICVC_REG_STRIDE)
  49#define LOGICVC_DTYPE_ROFF              (9  * LOGICVC_REG_STRIDE)
  50#define LOGICVC_BACKGROUND_COLOR_ROFF   (10 * LOGICVC_REG_STRIDE)
  51#define LOGICVC_DOUBLE_CLUT_ROFF        (12 * LOGICVC_REG_STRIDE)
  52#define LOGICVC_INT_STAT_ROFF           (13 * LOGICVC_REG_STRIDE)
  53#define LOGICVC_INT_MASK_ROFF           (14 * LOGICVC_REG_STRIDE)
  54#define LOGICVC_POWER_CTRL_ROFF         (15 * LOGICVC_REG_STRIDE)
  55#define LOGICVC_IP_VERSION_ROFF         (31 * LOGICVC_REG_STRIDE)
  56
  57/*
  58 * logiCVC layer registers offsets (common for each layer)
  59 * Last possible logiCVC layer (No.4) implements only "Layer memory address"
  60 * and "Layer control" registers.
  61 */
  62#define LOGICVC_LAYER_ADDR_ROFF         (0 * LOGICVC_REG_STRIDE)
  63#define LOGICVC_LAYER_HPOS_ROFF         (2 * LOGICVC_REG_STRIDE)
  64#define LOGICVC_LAYER_VPOS_ROFF         (3 * LOGICVC_REG_STRIDE)
  65#define LOGICVC_LAYER_HSIZE_ROFF        (4 * LOGICVC_REG_STRIDE)
  66#define LOGICVC_LAYER_VSIZE_ROFF        (5 * LOGICVC_REG_STRIDE)
  67#define LOGICVC_LAYER_ALPHA_ROFF        (6 * LOGICVC_REG_STRIDE)
  68#define LOGICVC_LAYER_CTRL_ROFF         (7 * LOGICVC_REG_STRIDE)
  69#define LOGICVC_LAYER_TRANSP_COLOR_ROFF (8 * LOGICVC_REG_STRIDE)
  70
  71/* logiCVC interrupt bits */
  72#define LOGICVC_INT_ALL \
  73                (LOGICVC_INT_L0_UPDATED | LOGICVC_INT_L1_UPDATED | \
  74                 LOGICVC_INT_L2_UPDATED | LOGICVC_INT_L3_UPDATED | \
  75                 LOGICVC_INT_L4_UPDATED | LOGICVC_INT_V_SYNC | \
  76                 LOGICVC_INT_E_VIDEO_VALID | LOGICVC_INT_FIFO_UNDERRUN | \
  77                 LOGICVC_INT_L0_CLUT_SW | LOGICVC_INT_L1_CLUT_SW | \
  78                 LOGICVC_INT_L2_CLUT_SW | LOGICVC_INT_L3_CLUT_SW | \
  79                 LOGICVC_INT_L4_CLUT_SW)
  80#define LOGICVC_INT_GENERAL \
  81                (LOGICVC_INT_L0_UPDATED | LOGICVC_INT_L1_UPDATED | \
  82                 LOGICVC_INT_L2_UPDATED | LOGICVC_INT_L3_UPDATED | \
  83                 LOGICVC_INT_L4_UPDATED | LOGICVC_INT_FIFO_UNDERRUN)
  84
  85/* logiCVC layer base offsets */
  86#define LOGICVC_LAYER_OFFSET            0x80
  87#define LOGICVC_LAYER_BASE_OFFSET       0x100
  88#define LOGICVC_LAYER_0_OFFSET          (0 * LOGICVC_LAYER_OFFSET)
  89#define LOGICVC_LAYER_1_OFFSET          (1 * LOGICVC_LAYER_OFFSET)
  90#define LOGICVC_LAYER_2_OFFSET          (2 * LOGICVC_LAYER_OFFSET)
  91#define LOGICVC_LAYER_3_OFFSET          (3 * LOGICVC_LAYER_OFFSET)
  92#define LOGICVC_LAYER_4_OFFSET          (4 * LOGICVC_LAYER_OFFSET)
  93
  94/*
  95 * logiCVC layer CLUT base offsets
  96 */
  97#define LOGICVC_CLUT_OFFSET             0x800
  98#define LOGICVC_CLUT_BASE_OFFSET        0x1000
  99#define LOGICVC_CLUT_L0_CLUT_0_OFFSET   (0 * LOGICVC_CLUT_OFFSET)
 100#define LOGICVC_CLUT_L0_CLUT_1_OFFSET   (1 * LOGICVC_CLUT_OFFSET)
 101#define LOGICVC_CLUT_L1_CLUT_0_OFFSET   (2 * LOGICVC_CLUT_OFFSET)
 102#define LOGICVC_CLUT_L1_CLUT_1_OFFSET   (3 * LOGICVC_CLUT_OFFSET)
 103#define LOGICVC_CLUT_L2_CLUT_0_OFFSET   (4 * LOGICVC_CLUT_OFFSET)
 104#define LOGICVC_CLUT_L2_CLUT_1_OFFSET   (5 * LOGICVC_CLUT_OFFSET)
 105#define LOGICVC_CLUT_L3_CLUT_0_OFFSET   (6 * LOGICVC_CLUT_OFFSET)
 106#define LOGICVC_CLUT_L3_CLUT_1_OFFSET   (7 * LOGICVC_CLUT_OFFSET)
 107#define LOGICVC_CLUT_L4_CLUT_0_OFFSET   (8 * LOGICVC_CLUT_OFFSET)
 108#define LOGICVC_CLUT_L4_CLUT_1_OFFSET   (9 * LOGICVC_CLUT_OFFSET)
 109#define LOGICVC_CLUT_REGISTER_SIZE      8
 110#define LOGICVC_CLUT_0_INDEX_OFFSET     2
 111#define LOGICVC_CLUT_1_INDEX_OFFSET     1
 112
 113/* logiCVC control register bits */
 114#define LOGICVC_CTRL_HSYNC                      (1 << 0)
 115#define LOGICVC_CTRL_HSYNC_INVERT               (1 << 1)
 116#define LOGICVC_CTRL_VSYNC                      (1 << 2)
 117#define LOGICVC_CTRL_VSYNC_INVERT               (1 << 3)
 118#define LOGICVC_CTRL_DATA_ENABLE                (1 << 4)
 119#define LOGICVC_CTRL_DATA_ENABLE_INVERT         (1 << 5)
 120#define LOGICVC_CTRL_PIXEL_DATA_INVERT          (1 << 7)
 121#define LOGICVC_CTRL_PIXEL_DATA_TRIGGER_INVERT  (1 << 8)
 122#define LOGICVC_CTRL_DISABLE_LAYER_UPDATE       (1 << 9)
 123
 124/* logiCVC layer control register bits */
 125#define LOGICVC_LAYER_CTRL_ENABLE                       (1 << 0)
 126#define LOGICVC_LAYER_CTRL_COLOR_TRANSPARENCY_BIT       (1 << 1)
 127#define LOGICVC_LAYER_CTRL_INTERLACE_BIT                (1 << 3)
 128
 129/* logiCVC control registers initial values */
 130#define LOGICVC_DTYPE_REG_INIT 0
 131
 132/* logiCVC various definitions */
 133#define LOGICVC_MAJOR_REVISION_SHIFT    11
 134#define LOGICVC_MAJOR_REVISION_MASK     0x3F
 135#define LOGICVC_MINOR_REVISION_SHIFT    5
 136#define LOGICVC_MINOR_REVISION_MASK     0x3F
 137#define LOGICVC_PATCH_LEVEL_MASK        0x1F
 138
 139#define LOGICVC_MIN_HRES        64
 140#define LOGICVC_MIN_VRES        1
 141#define LOGICVC_MAX_HRES        2048
 142#define LOGICVC_MAX_VRES        2048
 143#define LOGICVC_MAX_LINES       4096
 144#define LOGICVC_MAX_LAYERS      5
 145
 146#define LOGICVC_FLAGS_READABLE_REGS             (1 << 0)
 147#define LOGICVC_FLAGS_SIZE_POSITION             (1 << 1)
 148#define LOGICVC_FLAGS_BACKGROUND_LAYER          (1 << 2)
 149#define LOGICVC_FLAGS_BACKGROUND_LAYER_RGB      (1 << 3)
 150#define LOGICVC_FLAGS_BACKGROUND_LAYER_YUV      (1 << 4)
 151
 152#define LOGICVC_COLOR_RGB_BLACK         0
 153#define LOGICVC_COLOR_RGB_WHITE         0xFFFFFF
 154#define LOGICVC_COLOR_RGB565_WHITE      0xFFFF
 155#define LOGICVC_COLOR_YUV888_BLACK      0x8080
 156#define LOGICVC_COLOR_YUV888_WHITE      0xFF8080
 157
 158enum xylon_cvc_layer_type {
 159        LOGICVC_LAYER_RGB,
 160        LOGICVC_LAYER_YUV
 161};
 162
 163enum xylon_cvc_layer_alpha_type {
 164        LOGICVC_ALPHA_LAYER,
 165        LOGICVC_ALPHA_PIXEL,
 166        LOGICVC_ALPHA_CLUT_16BPP,
 167        LOGICVC_ALPHA_CLUT_32BPP
 168};
 169
 170enum xylon_cvc_display_color_space {
 171        LOGICVC_DCS_RGB,
 172        LOGICVC_DCS_YUV422,
 173        LOGICVC_DCS_YUV444
 174};
 175
 176struct xylon_cvc_layer_data;
 177
 178struct xylon_cvc_register_access {
 179        u32 (*xylon_cvc_get_reg_val)(void __iomem *reg_base_virt,
 180                                     unsigned int offset,
 181                                     struct xylon_cvc_layer_data *layer_data);
 182        void (*xylon_cvc_set_reg_val)(u32 value, void __iomem *reg_base_virt,
 183                                      unsigned int offset,
 184                                      struct xylon_cvc_layer_data *layer_data);
 185};
 186
 187struct xylon_cvc_registers {
 188        u32 ctrl;
 189        u32 dtype;
 190        u32 bg;
 191        u32 unused[3];
 192        u32 imr;
 193};
 194
 195struct xylon_cvc_layer_fix_data {
 196        unsigned int id;
 197        u32 address;
 198        u32 bpp;
 199        u32 type;
 200        u32 transparency;
 201        u32 width;
 202};
 203
 204struct xylon_cvc_layer_registers {
 205        u32 addr;
 206        u32 unused;
 207        u32 hpos;
 208        u32 vpos;
 209        u32 hsize;
 210        u32 vsize;
 211        u32 alpha;
 212        u32 ctrl;
 213        u32 transp;
 214};
 215
 216struct xylon_cvc_layer_data {
 217        struct xylon_cvc_layer_fix_data fix_data;
 218        struct xylon_cvc_layer_registers regs;
 219        void __iomem *base;
 220        void __iomem *clut_base;
 221        dma_addr_t vmem_pbase;
 222        struct xylon_cvc *cvc;
 223};
 224
 225struct xylon_cvc {
 226        struct device_node *dn;
 227        void __iomem *base;
 228        struct videomode *vmode;
 229        struct xylon_cvc_register_access reg_access;
 230        struct xylon_cvc_registers regs;
 231        struct xylon_cvc_layer_data *layer_data[LOGICVC_MAX_LAYERS];
 232        unsigned int flags;
 233        unsigned int irq;
 234        unsigned int layers;
 235        unsigned int power_on_delay;
 236        unsigned int signal_on_delay;
 237        u32 bg_layer_bpp;
 238        u32 ctrl;
 239        u32 pixel_stride;
 240};
 241
 242static u32 xylon_cvc_get_reg(void __iomem *base,
 243                             unsigned int offset,
 244                             struct xylon_cvc_layer_data *layer_data)
 245{
 246        return readl(base + offset);
 247}
 248
 249static void xylon_cvc_set_reg(u32 value, void __iomem *base,
 250                              unsigned int offset,
 251                              struct xylon_cvc_layer_data *layer_data)
 252{
 253        writel(value, base + offset);
 254}
 255
 256static unsigned long
 257xylon_cvc_get_reg_mem_addr(void __iomem *base, unsigned int offset,
 258                           struct xylon_cvc_layer_data *layer_data)
 259{
 260        unsigned int ordinal = offset / LOGICVC_REG_STRIDE;
 261
 262        if ((unsigned long)base - (unsigned long)layer_data->cvc->base) {
 263                return (unsigned long)(&layer_data->regs) +
 264                        (ordinal * sizeof(u32));
 265        } else {
 266                ordinal -= (LOGICVC_CTRL_ROFF / LOGICVC_REG_STRIDE);
 267                return (unsigned long)(&layer_data->cvc->regs) +
 268                                       (ordinal * sizeof(u32));
 269        }
 270}
 271
 272static u32 xylon_cvc_get_reg_mem(void __iomem *base, unsigned int offset,
 273                                 struct xylon_cvc_layer_data *layer_data)
 274{
 275        return *((unsigned long *)xylon_cvc_get_reg_mem_addr(base, offset,
 276                                                             layer_data));
 277}
 278
 279static void xylon_cvc_set_reg_mem(u32 value, void __iomem *base,
 280                                  unsigned int offset,
 281                                  struct xylon_cvc_layer_data *layer_data)
 282{
 283        unsigned long *reg_mem_addr =
 284                (unsigned long *)xylon_cvc_get_reg_mem_addr(base, offset,
 285                                                            layer_data);
 286        *reg_mem_addr = value;
 287        writel((*reg_mem_addr), (base + offset));
 288}
 289
 290unsigned int xylon_cvc_layer_get_total_count(struct xylon_cvc *cvc)
 291{
 292        return cvc->layers;
 293}
 294
 295u32 xylon_cvc_layer_get_format(struct xylon_cvc *cvc, int id)
 296{
 297        struct xylon_cvc_layer_data *layer_data = cvc->layer_data[id];
 298        u32 drm_format = 0;
 299        u32 bpp = layer_data->fix_data.bpp;
 300        u32 transp = layer_data->fix_data.transparency;
 301
 302        switch (layer_data->fix_data.type) {
 303        case LOGICVC_LAYER_RGB:
 304                if (bpp == 16 && transp == LOGICVC_ALPHA_LAYER)
 305                        drm_format = DRM_FORMAT_RGB565;
 306                else if (bpp == 32 && transp == LOGICVC_ALPHA_LAYER)
 307                        drm_format = DRM_FORMAT_XRGB8888;
 308                else if (bpp == 32 && transp == LOGICVC_ALPHA_PIXEL)
 309                        drm_format = DRM_FORMAT_ARGB8888;
 310                break;
 311        case LOGICVC_LAYER_YUV:
 312                if (bpp == 16 && transp == LOGICVC_ALPHA_LAYER)
 313                        drm_format = DRM_FORMAT_YUYV;
 314                else if (bpp == 32 && transp == LOGICVC_ALPHA_LAYER)
 315                        drm_format = DRM_FORMAT_YUYV;
 316                break;
 317        default:
 318                DRM_ERROR("unsupported layer format\n");
 319        }
 320
 321        return drm_format;
 322}
 323
 324unsigned int xylon_cvc_layer_get_bits_per_pixel(struct xylon_cvc *cvc, int id)
 325{
 326        struct xylon_cvc_layer_data *layer_data = cvc->layer_data[id];
 327
 328        return layer_data->fix_data.bpp;
 329}
 330
 331void xylon_cvc_layer_set_alpha(struct xylon_cvc *cvc, int id, u8 alpha)
 332{
 333        struct xylon_cvc_layer_data *layer_data = cvc->layer_data[id];
 334        struct xylon_cvc_layer_fix_data *fix_data = &layer_data->fix_data;
 335        struct xylon_cvc_register_access *reg_access = &cvc->reg_access;
 336        u32 alpha32 = alpha;
 337
 338        if (fix_data->transparency == LOGICVC_ALPHA_LAYER)
 339                reg_access->xylon_cvc_set_reg_val(alpha32, layer_data->base,
 340                                                  LOGICVC_LAYER_ALPHA_ROFF,
 341                                                  layer_data);
 342}
 343
 344int xylon_cvc_layer_set_size_position(struct xylon_cvc *cvc, int id,
 345                                      int src_x, int src_y,
 346                                      unsigned int src_x_size,
 347                                      unsigned int src_y_size,
 348                                      int dst_x, int dst_y,
 349                                      unsigned int dst_x_size,
 350                                      unsigned int dst_y_size)
 351{
 352        struct xylon_cvc_layer_data *layer_data = cvc->layer_data[id];
 353        struct xylon_cvc_register_access *reg_access = &cvc->reg_access;
 354        void __iomem *base = layer_data->base;
 355        u32 hres, vres;
 356
 357        DRM_DEBUG("%d-%d(%d-%d), %d-%d(%d-%d)\n",
 358                  src_x, dst_x, src_x_size, dst_x_size,
 359                  src_y, dst_y, src_y_size, dst_y_size);
 360
 361        if (src_x_size != dst_x_size || src_y_size != dst_y_size) {
 362                DRM_ERROR("invalid source coordinates\n");
 363                return -EINVAL;
 364        }
 365
 366        if (cvc->vmode) {
 367                hres = cvc->vmode->hactive;
 368                vres = cvc->vmode->vactive;
 369
 370                if ((dst_x + dst_x_size) > hres ||
 371                    (dst_y + dst_y_size) > vres) {
 372                        DRM_ERROR("invalid rectangle width\n");
 373                        return -EINVAL;
 374                }
 375
 376                reg_access->xylon_cvc_set_reg_val(hres - dst_x - 1,
 377                                                  base,
 378                                                  LOGICVC_LAYER_HPOS_ROFF,
 379                                                  layer_data);
 380                reg_access->xylon_cvc_set_reg_val(vres - dst_y - 1,
 381                                                  base,
 382                                                  LOGICVC_LAYER_VPOS_ROFF,
 383                                                  layer_data);
 384                reg_access->xylon_cvc_set_reg_val(dst_x_size - 1,
 385                                                  base,
 386                                                  LOGICVC_LAYER_HSIZE_ROFF,
 387                                                  layer_data);
 388                reg_access->xylon_cvc_set_reg_val(dst_y_size - 1,
 389                                                  base,
 390                                                  LOGICVC_LAYER_VSIZE_ROFF,
 391                                                  layer_data);
 392        }
 393
 394        return 0;
 395}
 396
 397void xylon_cvc_layer_set_address(struct xylon_cvc *cvc, int id,
 398                                 dma_addr_t paddr, u32 x, u32 y)
 399{
 400        struct xylon_cvc_layer_data *layer_data = cvc->layer_data[id];
 401        u32 vmem_offset;
 402
 403        vmem_offset = (x * (layer_data->fix_data.bpp / 8)) +
 404                      (y * layer_data->fix_data.width *
 405                      (layer_data->fix_data.bpp / 8));
 406
 407        layer_data->vmem_pbase = paddr + vmem_offset;
 408}
 409
 410void xylon_cvc_layer_enable(struct xylon_cvc *cvc, int id)
 411{
 412        struct xylon_cvc_layer_data *layer_data = cvc->layer_data[id];
 413        struct xylon_cvc_register_access *reg_access = &cvc->reg_access;
 414        u32 regval = reg_access->xylon_cvc_get_reg_val(layer_data->base,
 415                                                       LOGICVC_LAYER_CTRL_ROFF,
 416                                                       layer_data);
 417
 418        regval |= LOGICVC_LAYER_CTRL_ENABLE;
 419        reg_access->xylon_cvc_set_reg_val(regval,
 420                                          layer_data->base,
 421                                          LOGICVC_LAYER_CTRL_ROFF,
 422                                          layer_data);
 423}
 424
 425void xylon_cvc_layer_disable(struct xylon_cvc *cvc, int id)
 426{
 427        struct xylon_cvc_layer_data *layer_data = cvc->layer_data[id];
 428        struct xylon_cvc_register_access *reg_access = &cvc->reg_access;
 429        u32 regval = reg_access->xylon_cvc_get_reg_val(layer_data->base,
 430                                                       LOGICVC_LAYER_CTRL_ROFF,
 431                                                       layer_data);
 432
 433        regval &= (~LOGICVC_LAYER_CTRL_ENABLE);
 434        reg_access->xylon_cvc_set_reg_val(regval,
 435                                          layer_data->base,
 436                                          LOGICVC_LAYER_CTRL_ROFF,
 437                                          layer_data);
 438}
 439
 440void xylon_cvc_layer_update(struct xylon_cvc *cvc, int id)
 441{
 442        struct xylon_cvc_layer_data *layer_data = cvc->layer_data[id];
 443        struct xylon_cvc_register_access *reg_access = &cvc->reg_access;
 444
 445        reg_access->xylon_cvc_set_reg_val(layer_data->vmem_pbase,
 446                                          layer_data->base,
 447                                          LOGICVC_LAYER_ADDR_ROFF,
 448                                          layer_data);
 449}
 450
 451void xylon_cvc_layer_ctrl(struct xylon_cvc *cvc, int id,
 452                          enum xylon_cvc_layer_control op)
 453{
 454        struct xylon_cvc_layer_data *layer_data = cvc->layer_data[id];
 455        struct xylon_cvc_register_access *reg_access = &cvc->reg_access;
 456        u32 regval = reg_access->xylon_cvc_get_reg_val(layer_data->base,
 457                                                       LOGICVC_LAYER_CTRL_ROFF,
 458                                                       layer_data);
 459
 460        switch (op) {
 461        case LOGICVC_LAYER_COLOR_TRANSPARENCY_DISABLE:
 462                regval |= LOGICVC_LAYER_CTRL_COLOR_TRANSPARENCY_BIT;
 463                break;
 464        case LOGICVC_LAYER_COLOR_TRANSPARENCY_ENABLE:
 465                regval &= ~LOGICVC_LAYER_CTRL_COLOR_TRANSPARENCY_BIT;
 466                break;
 467        case LOGICVC_LAYER_INTERLACE_DISABLE:
 468                regval |= LOGICVC_LAYER_CTRL_INTERLACE_BIT;
 469                break;
 470        case LOGICVC_LAYER_INTERLACE_ENABLE:
 471                regval &= ~LOGICVC_LAYER_CTRL_INTERLACE_BIT;
 472                break;
 473        default:
 474                return;
 475        }
 476
 477        reg_access->xylon_cvc_set_reg_val(regval,
 478                                          layer_data->base,
 479                                          LOGICVC_LAYER_CTRL_ROFF,
 480                                          layer_data);
 481}
 482
 483void xylon_cvc_layer_set_color_reg(struct xylon_cvc *cvc, int id, u32 color)
 484{
 485        struct xylon_cvc_layer_data *layer_data;
 486        void __iomem *base;
 487        unsigned int layer_bpp;
 488        unsigned long offset;
 489        u8 r, g, b;
 490        bool bg = false;
 491
 492        if (id == BACKGROUND_LAYER_ID)
 493                bg = true;
 494
 495        if (bg) {
 496                if (!(cvc->flags & LOGICVC_FLAGS_BACKGROUND_LAYER))
 497                        return;
 498                layer_data = cvc->layer_data[0];
 499                layer_bpp = cvc->bg_layer_bpp;
 500        } else {
 501                layer_data = cvc->layer_data[id];
 502                layer_bpp = layer_data->fix_data.bpp;
 503        }
 504
 505        switch (layer_bpp) {
 506        case 16:
 507                color &= LOGICVC_COLOR_RGB_WHITE;
 508                if (cvc->flags & LOGICVC_FLAGS_BACKGROUND_LAYER_RGB &&
 509                    (color != LOGICVC_COLOR_RGB_BLACK)) {
 510                        if (color != LOGICVC_COLOR_RGB_WHITE) {
 511                                r = color >> 16;
 512                                g = color >> 8;
 513                                b = color;
 514
 515                                color = ((r & 0xF8) << 8) |
 516                                        ((g & 0xFC) << 3) |
 517                                        ((b & 0xF8) >> 3);
 518                        } else {
 519                                color = LOGICVC_COLOR_RGB565_WHITE;
 520                        }
 521                }
 522                break;
 523        case 32:
 524                if (cvc->flags & LOGICVC_FLAGS_BACKGROUND_LAYER_YUV) {
 525                        if (color == LOGICVC_COLOR_RGB_BLACK)
 526                                color = LOGICVC_COLOR_YUV888_BLACK;
 527                        else if (color == LOGICVC_COLOR_RGB_WHITE)
 528                                color = LOGICVC_COLOR_YUV888_WHITE;
 529                }
 530                break;
 531        default:
 532                if (cvc->flags & LOGICVC_FLAGS_BACKGROUND_LAYER_YUV)
 533                        color = LOGICVC_COLOR_YUV888_BLACK;
 534                else
 535                        color = LOGICVC_COLOR_RGB_BLACK;
 536                DRM_INFO("unsupported bg layer bpp\n");
 537                return;
 538        }
 539
 540        if (bg) {
 541                base = cvc->base;
 542                offset = LOGICVC_BACKGROUND_COLOR_ROFF;
 543        } else {
 544                base = layer_data->base;
 545                offset = LOGICVC_LAYER_TRANSP_COLOR_ROFF;
 546        }
 547        cvc->reg_access.xylon_cvc_set_reg_val(color,
 548                                              base, offset,
 549                                              layer_data);
 550}
 551
 552void xylon_cvc_int_state(struct xylon_cvc *cvc, unsigned int type,
 553                         bool enabled)
 554{
 555        struct xylon_cvc_layer_data *layer_data = cvc->layer_data[0];
 556        struct xylon_cvc_register_access *reg_access = &cvc->reg_access;
 557        void __iomem *base = cvc->base;
 558        u32 imr = reg_access->xylon_cvc_get_reg_val(base,
 559                                                    LOGICVC_INT_MASK_ROFF,
 560                                                    layer_data);
 561        if (enabled)
 562                imr &= ~type;
 563        else
 564                imr |= type;
 565
 566        reg_access->xylon_cvc_set_reg_val(imr, base,
 567                                          LOGICVC_INT_MASK_ROFF,
 568                                          layer_data);
 569}
 570
 571u32 xylon_cvc_int_get_active(struct xylon_cvc *cvc)
 572{
 573        return readl(cvc->base + LOGICVC_INT_STAT_ROFF);
 574}
 575
 576void xylon_cvc_int_clear_active(struct xylon_cvc *cvc, u32 active)
 577{
 578        writel(active, cvc->base + LOGICVC_INT_STAT_ROFF);
 579}
 580
 581void xylon_cvc_int_hw_enable(struct xylon_cvc *cvc)
 582{
 583        struct xylon_cvc_layer_data *layer_data = cvc->layer_data[0];
 584        struct xylon_cvc_register_access *reg_access = &cvc->reg_access;
 585        void __iomem *base = cvc->base;
 586
 587        reg_access->xylon_cvc_set_reg_val(LOGICVC_INT_GENERAL, base,
 588                                          LOGICVC_INT_MASK_ROFF,
 589                                          layer_data);
 590        writel(LOGICVC_INT_ALL, base + LOGICVC_INT_STAT_ROFF);
 591}
 592
 593void xylon_cvc_int_hw_disable(struct xylon_cvc *cvc)
 594{
 595        struct xylon_cvc_layer_data *layer_data = cvc->layer_data[0];
 596        struct xylon_cvc_register_access *reg_access = &cvc->reg_access;
 597        void __iomem *base = cvc->base;
 598
 599        reg_access->xylon_cvc_set_reg_val(LOGICVC_INT_ALL, base,
 600                                          LOGICVC_INT_MASK_ROFF,
 601                                          layer_data);
 602        writel(LOGICVC_INT_ALL, base + LOGICVC_INT_STAT_ROFF);
 603}
 604
 605int xylon_cvc_int_request(struct xylon_cvc *cvc, unsigned long flags,
 606                          irq_handler_t handler, void *dev)
 607{
 608        struct device_node *dn = cvc->dn;
 609        int irq;
 610
 611        irq = of_irq_to_resource(dn, 0, NULL);
 612        if (irq < 0) {
 613                DRM_ERROR("failed get irq resource\n");
 614                return irq;
 615        }
 616
 617        cvc->irq = irq;
 618
 619        return request_irq(irq, handler, flags, dn->name, dev);
 620}
 621
 622void xylon_cvc_int_free(struct xylon_cvc *cvc, void *dev)
 623{
 624        free_irq(cvc->irq, dev);
 625}
 626
 627void xylon_cvc_ctrl(struct xylon_cvc *cvc, enum xylon_cvc_control ctrl,
 628                    bool val)
 629{
 630        struct xylon_cvc_layer_data *layer_data = cvc->layer_data[0];
 631
 632        switch (ctrl) {
 633        case LOGICVC_LAYER_UPDATE:
 634                if (val)
 635                        cvc->ctrl &= ~LOGICVC_CTRL_DISABLE_LAYER_UPDATE;
 636                else
 637                        cvc->ctrl |= LOGICVC_CTRL_DISABLE_LAYER_UPDATE;
 638                break;
 639        case LOGICVC_PIXEL_DATA_TRIGGER_INVERT:
 640                if (val)
 641                        cvc->ctrl |= LOGICVC_CTRL_PIXEL_DATA_TRIGGER_INVERT;
 642                else
 643                        cvc->ctrl &= ~LOGICVC_CTRL_PIXEL_DATA_TRIGGER_INVERT;
 644                break;
 645        case LOGICVC_PIXEL_DATA_INVERT:
 646                if (val)
 647                        cvc->ctrl |= LOGICVC_CTRL_PIXEL_DATA_INVERT;
 648                else
 649                        cvc->ctrl &= ~LOGICVC_CTRL_PIXEL_DATA_INVERT;
 650                break;
 651        }
 652
 653        cvc->reg_access.xylon_cvc_set_reg_val(cvc->ctrl, cvc->base,
 654                                              LOGICVC_CTRL_ROFF,
 655                                              layer_data);
 656}
 657
 658void xylon_cvc_enable(struct xylon_cvc *cvc, struct videomode *vmode)
 659{
 660        void __iomem *base = cvc->base;
 661        struct xylon_cvc_layer_data *layer_data = cvc->layer_data[0];
 662        struct videomode *vm;
 663
 664        if (vmode) {
 665                cvc->vmode = vmode;
 666                vm = vmode;
 667        } else {
 668                vm = cvc->vmode;
 669        }
 670
 671        writel(vm->hfront_porch - 1, base + LOGICVC_HSYNC_FRONT_PORCH_ROFF);
 672        writel(vm->hsync_len - 1, base + LOGICVC_HSYNC_ROFF);
 673        writel(vm->hback_porch - 1, base + LOGICVC_HSYNC_BACK_PORCH_ROFF);
 674        writel(vm->hactive - 1, base + LOGICVC_HRES_ROFF);
 675        writel(vm->vfront_porch - 1, base + LOGICVC_VSYNC_FRONT_PORCH_ROFF);
 676        writel(vm->vsync_len - 1, base + LOGICVC_VSYNC_ROFF);
 677        writel(vm->vback_porch - 1, base + LOGICVC_VSYNC_BACK_PORCH_ROFF);
 678        writel(vm->vactive - 1, base + LOGICVC_VRES_ROFF);
 679
 680        cvc->reg_access.xylon_cvc_set_reg_val(cvc->ctrl, base,
 681                                              LOGICVC_CTRL_ROFF,
 682                                              layer_data);
 683
 684        writel(LOGICVC_DTYPE_REG_INIT, base + LOGICVC_DTYPE_ROFF);
 685}
 686
 687void xylon_cvc_disable(struct xylon_cvc *cvc)
 688{
 689        struct xylon_cvc_layer_data *layer_data = cvc->layer_data[0];
 690        int i;
 691
 692        if (layer_data)
 693                for (i = 0; i < cvc->layers; i++)
 694                        xylon_cvc_layer_disable(cvc, i);
 695}
 696
 697static int xylon_parse_hw_info(struct device_node *dn, struct xylon_cvc *cvc)
 698{
 699        int ret;
 700        const char *string;
 701
 702        if (of_property_read_bool(dn, "background-layer-bits-per-pixel")) {
 703                ret = of_property_read_u32(dn,
 704                                           "background-layer-bits-per-pixel",
 705                                           &cvc->bg_layer_bpp);
 706                if (ret) {
 707                        DRM_ERROR("failed get bg-layer-bits-per-pixel\n");
 708                        return ret;
 709                }
 710                cvc->flags |= LOGICVC_FLAGS_BACKGROUND_LAYER;
 711
 712                ret = of_property_read_string(dn, "background-layer-type",
 713                                              &string);
 714                if (ret) {
 715                        DRM_ERROR("failed get bg-layer-type\n");
 716                        return ret;
 717                }
 718                if (!strcmp(string, "rgb")) {
 719                        cvc->flags |= LOGICVC_FLAGS_BACKGROUND_LAYER_RGB;
 720                } else if (!strcmp(string, "yuv")) {
 721                        cvc->flags |= LOGICVC_FLAGS_BACKGROUND_LAYER_YUV;
 722                } else {
 723                        DRM_ERROR("unsupported bg layer type\n");
 724                        return -EINVAL;
 725                }
 726        }
 727
 728        if (of_property_read_bool(dn, "readable-regs"))
 729                cvc->flags |= LOGICVC_FLAGS_READABLE_REGS;
 730        else
 731                DRM_INFO("logicvc registers not readable\n");
 732
 733        if (of_property_read_bool(dn, "size-position"))
 734                cvc->flags |= LOGICVC_FLAGS_SIZE_POSITION;
 735        else
 736                DRM_INFO("logicvc size-position disabled\n");
 737
 738        ret = of_property_read_u32(dn, "pixel-stride", &cvc->pixel_stride);
 739        if (ret) {
 740                DRM_ERROR("failed get pixel-stride\n");
 741                return ret;
 742        }
 743
 744        return 0;
 745}
 746
 747static int xylonfb_parse_layer_info(struct device *dev,
 748                                    struct device_node *parent_dn,
 749                                    struct xylon_cvc *cvc, int id)
 750{
 751        struct device_node *dn;
 752        struct xylon_cvc_layer_data *layer_data;
 753        int ret;
 754        char layer_name[10];
 755        const char *string;
 756
 757        snprintf(layer_name, sizeof(layer_name), "layer_%d", id);
 758        dn = of_get_child_by_name(parent_dn, layer_name);
 759        if (!dn)
 760                return 0;
 761
 762        cvc->layers++;
 763
 764        layer_data = devm_kzalloc(dev, sizeof(*layer_data), GFP_KERNEL);
 765        if (!layer_data) {
 766                DRM_ERROR("failed allocate layer data id %d\n", id);
 767                return -ENOMEM;
 768        }
 769        layer_data->cvc = cvc;
 770        layer_data->fix_data.id = id;
 771
 772        cvc->layer_data[id] = layer_data;
 773
 774        if (of_property_read_bool(dn, "address")) {
 775                ret = of_property_read_u32(dn, "address",
 776                                           &layer_data->fix_data.address);
 777                if (ret) {
 778                        DRM_ERROR("failed get address\n");
 779                        return ret;
 780                }
 781        }
 782
 783        ret = of_property_read_u32(dn, "bits-per-pixel",
 784                                   &layer_data->fix_data.bpp);
 785        if (ret) {
 786                DRM_ERROR("failed get bits-per-pixel\n");
 787                return ret;
 788        }
 789
 790        ret = of_property_read_string(dn, "type", &string);
 791        if (ret) {
 792                DRM_ERROR("failed get type\n");
 793                return ret;
 794        }
 795        if (!strcmp(string, "rgb")) {
 796                layer_data->fix_data.type = LOGICVC_LAYER_RGB;
 797        } else if (!strcmp(string, "yuv")) {
 798                layer_data->fix_data.type = LOGICVC_LAYER_YUV;
 799        } else {
 800                DRM_ERROR("unsupported layer type\n");
 801                return -EINVAL;
 802        }
 803
 804        ret = of_property_read_string(dn, "transparency", &string);
 805        if (ret) {
 806                DRM_ERROR("failed get transparency\n");
 807                return ret;
 808        }
 809        if (!strcmp(string, "layer")) {
 810                layer_data->fix_data.transparency = LOGICVC_ALPHA_LAYER;
 811        } else if (!strcmp(string, "pixel")) {
 812                layer_data->fix_data.transparency = LOGICVC_ALPHA_PIXEL;
 813        } else {
 814                DRM_ERROR("unsupported layer transparency\n");
 815                return -EINVAL;
 816        }
 817
 818        layer_data->fix_data.width = cvc->pixel_stride;
 819
 820        return id + 1;
 821}
 822
 823static void xylon_cvc_init_ctrl(struct device_node *dn, u32 *ctrl)
 824{
 825        u32 ctrl_reg = (LOGICVC_CTRL_HSYNC | LOGICVC_CTRL_VSYNC |
 826                        LOGICVC_CTRL_DATA_ENABLE);
 827
 828        if (of_property_read_bool(dn, "hsync-active-low"))
 829                ctrl_reg |= LOGICVC_CTRL_HSYNC_INVERT;
 830        if (of_property_read_bool(dn, "vsync-active-low"))
 831                ctrl_reg |= LOGICVC_CTRL_HSYNC_INVERT;
 832        if (of_property_read_bool(dn, "pixel-data-invert"))
 833                ctrl_reg |= LOGICVC_CTRL_PIXEL_DATA_INVERT;
 834        if (of_property_read_bool(dn, "pixel-data-output-trigger-high"))
 835                ctrl_reg |= LOGICVC_CTRL_PIXEL_DATA_TRIGGER_INVERT;
 836
 837        *ctrl = ctrl_reg;
 838}
 839
 840bool xylon_cvc_get_info(struct xylon_cvc *cvc, enum xylon_cvc_info info,
 841                        unsigned int param)
 842{
 843        struct xylon_cvc_layer_data *layer_data;
 844        struct xylon_cvc_register_access *reg_access;
 845
 846        switch (info) {
 847        case LOGICVC_INFO_BACKGROUND_LAYER:
 848                if (cvc->flags & LOGICVC_FLAGS_BACKGROUND_LAYER)
 849                        return true;
 850                break;
 851        case LOGICVC_INFO_LAST_LAYER:
 852                if (param == (cvc->layers - 1))
 853                        return true;
 854                break;
 855        case LOGICVC_INFO_LAYER_COLOR_TRANSPARENCY:
 856                layer_data = cvc->layer_data[param];
 857                reg_access = &cvc->reg_access;
 858                if (!(reg_access->xylon_cvc_get_reg_val(layer_data->base,
 859                                                        LOGICVC_LAYER_CTRL_ROFF,
 860                                                        layer_data) &
 861                    LOGICVC_LAYER_CTRL_COLOR_TRANSPARENCY_BIT))
 862                        return true;
 863                break;
 864        case LOGICVC_INFO_LAYER_UPDATE:
 865                if (!(cvc->ctrl & LOGICVC_CTRL_DISABLE_LAYER_UPDATE))
 866                        return true;
 867                break;
 868        case LOGICVC_INFO_PIXEL_DATA_INVERT:
 869                if (cvc->ctrl & LOGICVC_CTRL_PIXEL_DATA_INVERT)
 870                        return true;
 871                break;
 872        case LOGICVC_INFO_PIXEL_DATA_TRIGGER_INVERT:
 873                if (cvc->ctrl & LOGICVC_CTRL_PIXEL_DATA_TRIGGER_INVERT)
 874                        return true;
 875                break;
 876        case LOGICVC_INFO_SIZE_POSITION:
 877                if (cvc->flags & LOGICVC_FLAGS_SIZE_POSITION)
 878                        return true;
 879                break;
 880        }
 881
 882        return false;
 883}
 884
 885void xylon_cvc_get_fix_parameters(struct xylon_cvc *cvc,
 886                                  struct xylon_cvc_fix *cvc_fix)
 887{
 888        struct xylon_cvc_layer_data *layer_data = cvc->layer_data[0];
 889        struct xylon_cvc_layer_fix_data *fix_data = &layer_data->fix_data;
 890
 891        cvc_fix->hres_min = LOGICVC_MIN_HRES;
 892        cvc_fix->vres_min = LOGICVC_MIN_VRES;
 893        cvc_fix->hres_max = LOGICVC_MAX_HRES;
 894        cvc_fix->vres_max = LOGICVC_MAX_VRES;
 895        cvc_fix->x_min = LOGICVC_MIN_HRES;
 896        cvc_fix->y_min = LOGICVC_MIN_VRES;
 897        cvc_fix->x_max = fix_data->width;
 898        cvc_fix->y_max = LOGICVC_MAX_LINES;
 899}
 900
 901static const struct of_device_id cvc_of_match[] = {
 902        { .compatible = "xylon,logicvc-4.00.a" },
 903        { .compatible = "xylon,logicvc-5.0" },
 904        {/* end of table */}
 905};
 906
 907struct xylon_cvc *xylon_cvc_probe(struct device *dev, struct device_node *dn)
 908{
 909        struct xylon_cvc *cvc;
 910        const struct of_device_id *match;
 911        __force const void *err;
 912        struct resource res;
 913        u32 ip_ver;
 914        int ret, i;
 915        unsigned short xylon_cvc_layer_base_off[] = {
 916                (LOGICVC_LAYER_BASE_OFFSET + LOGICVC_LAYER_0_OFFSET),
 917                (LOGICVC_LAYER_BASE_OFFSET + LOGICVC_LAYER_1_OFFSET),
 918                (LOGICVC_LAYER_BASE_OFFSET + LOGICVC_LAYER_2_OFFSET),
 919                (LOGICVC_LAYER_BASE_OFFSET + LOGICVC_LAYER_3_OFFSET),
 920                (LOGICVC_LAYER_BASE_OFFSET + LOGICVC_LAYER_4_OFFSET)
 921        };
 922        unsigned short xylon_cvc_clut_base_off[] = {
 923                (LOGICVC_CLUT_BASE_OFFSET + LOGICVC_CLUT_L0_CLUT_0_OFFSET),
 924                (LOGICVC_CLUT_BASE_OFFSET + LOGICVC_CLUT_L0_CLUT_1_OFFSET),
 925                (LOGICVC_CLUT_BASE_OFFSET + LOGICVC_CLUT_L1_CLUT_0_OFFSET),
 926                (LOGICVC_CLUT_BASE_OFFSET + LOGICVC_CLUT_L1_CLUT_1_OFFSET),
 927                (LOGICVC_CLUT_BASE_OFFSET + LOGICVC_CLUT_L2_CLUT_0_OFFSET),
 928                (LOGICVC_CLUT_BASE_OFFSET + LOGICVC_CLUT_L2_CLUT_1_OFFSET),
 929                (LOGICVC_CLUT_BASE_OFFSET + LOGICVC_CLUT_L3_CLUT_0_OFFSET),
 930                (LOGICVC_CLUT_BASE_OFFSET + LOGICVC_CLUT_L3_CLUT_1_OFFSET),
 931                (LOGICVC_CLUT_BASE_OFFSET + LOGICVC_CLUT_L4_CLUT_0_OFFSET),
 932                (LOGICVC_CLUT_BASE_OFFSET + LOGICVC_CLUT_L4_CLUT_1_OFFSET)
 933        };
 934
 935        match = of_match_node(cvc_of_match, dn);
 936        if (!match) {
 937                DRM_ERROR("failed match cvc\n");
 938                return ERR_PTR(-ENODEV);
 939        }
 940
 941        cvc = devm_kzalloc(dev, sizeof(*cvc), GFP_KERNEL);
 942        if (!cvc) {
 943                DRM_ERROR("failed allocate cvc\n");
 944                return ERR_PTR(-ENOMEM);
 945        }
 946        cvc->dn = dn;
 947
 948        ret = of_address_to_resource(dn, 0, &res);
 949        if (ret) {
 950                DRM_ERROR("failed get mem resource\n");
 951                return ERR_PTR(ret);
 952        }
 953
 954        cvc->base = devm_ioremap_resource(dev, &res);
 955        err = (__force const void *)cvc->base;
 956        if (IS_ERR(err)) {
 957                DRM_ERROR("failed remap resource\n");
 958                return ERR_CAST(err);
 959        }
 960
 961        ip_ver = readl(cvc->base + LOGICVC_IP_VERSION_ROFF);
 962        DRM_INFO("logiCVC IP core %d.%02d.%c\n",
 963                 ((ip_ver >> LOGICVC_MAJOR_REVISION_SHIFT) &
 964                 LOGICVC_MAJOR_REVISION_MASK),
 965                 ((ip_ver >> LOGICVC_MINOR_REVISION_SHIFT) &
 966                 LOGICVC_MINOR_REVISION_MASK),
 967                 ((ip_ver & LOGICVC_PATCH_LEVEL_MASK) + 'a'));
 968
 969        ret = xylon_parse_hw_info(dn, cvc);
 970        if (ret)
 971                return ERR_PTR(ret);
 972
 973        for (i = 0; i < LOGICVC_MAX_LAYERS; i++) {
 974                ret = xylonfb_parse_layer_info(dev, dn, cvc, i);
 975                if (ret < 0)
 976                        return ERR_PTR(ret);
 977                if (ret == 0)
 978                        break;
 979
 980                cvc->layer_data[i]->base =
 981                        cvc->base + xylon_cvc_layer_base_off[i];
 982                cvc->layer_data[i]->clut_base =
 983                        cvc->base + xylon_cvc_clut_base_off[i];
 984        }
 985
 986        xylon_cvc_init_ctrl(dn, &cvc->ctrl);
 987
 988        if (cvc->flags & LOGICVC_FLAGS_READABLE_REGS) {
 989                cvc->reg_access.xylon_cvc_get_reg_val = xylon_cvc_get_reg;
 990                cvc->reg_access.xylon_cvc_set_reg_val = xylon_cvc_set_reg;
 991        } else {
 992                cvc->reg_access.xylon_cvc_get_reg_val = xylon_cvc_get_reg_mem;
 993                cvc->reg_access.xylon_cvc_set_reg_val = xylon_cvc_set_reg_mem;
 994        }
 995
 996        if (cvc->flags & LOGICVC_FLAGS_BACKGROUND_LAYER)
 997                xylon_cvc_layer_set_color_reg(cvc, BACKGROUND_LAYER_ID,
 998                                              LOGICVC_COLOR_RGB_BLACK);
 999
1000        return cvc;
1001}
1002