linux/drivers/gpu/drm/arm/malidp_hw.c
<<
>>
Prefs
   1/*
   2 * (C) COPYRIGHT 2016 ARM Limited. All rights reserved.
   3 * Author: Liviu Dudau <Liviu.Dudau@arm.com>
   4 *
   5 * This program is free software and is provided to you under the terms of the
   6 * GNU General Public License version 2 as published by the Free Software
   7 * Foundation, and any use by you of this program is subject to the terms
   8 * of such GNU licence.
   9 *
  10 * ARM Mali DP500/DP550/DP650 hardware manipulation routines. This is where
  11 * the difference between various versions of the hardware is being dealt with
  12 * in an attempt to provide to the rest of the driver code a unified view
  13 */
  14
  15#include <linux/clk.h>
  16#include <linux/types.h>
  17#include <linux/io.h>
  18#include <drm/drmP.h>
  19#include <video/videomode.h>
  20#include <video/display_timing.h>
  21
  22#include "malidp_drv.h"
  23#include "malidp_hw.h"
  24
  25static const struct malidp_format_id malidp500_de_formats[] = {
  26        /*    fourcc,   layers supporting the format,     internal id  */
  27        { DRM_FORMAT_ARGB2101010, DE_VIDEO1 | DE_GRAPHICS1 | DE_GRAPHICS2,  0 },
  28        { DRM_FORMAT_ABGR2101010, DE_VIDEO1 | DE_GRAPHICS1 | DE_GRAPHICS2,  1 },
  29        { DRM_FORMAT_ARGB8888, DE_VIDEO1 | DE_GRAPHICS1 | DE_GRAPHICS2,  2 },
  30        { DRM_FORMAT_ABGR8888, DE_VIDEO1 | DE_GRAPHICS1 | DE_GRAPHICS2,  3 },
  31        { DRM_FORMAT_XRGB8888, DE_VIDEO1 | DE_GRAPHICS1 | DE_GRAPHICS2,  4 },
  32        { DRM_FORMAT_XBGR8888, DE_VIDEO1 | DE_GRAPHICS1 | DE_GRAPHICS2,  5 },
  33        { DRM_FORMAT_RGB888, DE_VIDEO1 | DE_GRAPHICS1 | DE_GRAPHICS2,  6 },
  34        { DRM_FORMAT_BGR888, DE_VIDEO1 | DE_GRAPHICS1 | DE_GRAPHICS2,  7 },
  35        { DRM_FORMAT_RGBA5551, DE_VIDEO1 | DE_GRAPHICS1 | DE_GRAPHICS2,  8 },
  36        { DRM_FORMAT_ABGR1555, DE_VIDEO1 | DE_GRAPHICS1 | DE_GRAPHICS2,  9 },
  37        { DRM_FORMAT_RGB565, DE_VIDEO1 | DE_GRAPHICS1 | DE_GRAPHICS2, 10 },
  38        { DRM_FORMAT_BGR565, DE_VIDEO1 | DE_GRAPHICS1 | DE_GRAPHICS2, 11 },
  39        { DRM_FORMAT_UYVY, DE_VIDEO1, 12 },
  40        { DRM_FORMAT_YUYV, DE_VIDEO1, 13 },
  41        { DRM_FORMAT_NV12, DE_VIDEO1, 14 },
  42        { DRM_FORMAT_YUV420, DE_VIDEO1, 15 },
  43};
  44
  45#define MALIDP_ID(__group, __format) \
  46        ((((__group) & 0x7) << 3) | ((__format) & 0x7))
  47
  48#define MALIDP_COMMON_FORMATS \
  49        /*    fourcc,   layers supporting the format,      internal id   */ \
  50        { DRM_FORMAT_ARGB2101010, DE_VIDEO1 | DE_GRAPHICS1 | DE_VIDEO2, MALIDP_ID(0, 0) }, \
  51        { DRM_FORMAT_ABGR2101010, DE_VIDEO1 | DE_GRAPHICS1 | DE_VIDEO2, MALIDP_ID(0, 1) }, \
  52        { DRM_FORMAT_RGBA1010102, DE_VIDEO1 | DE_GRAPHICS1 | DE_VIDEO2, MALIDP_ID(0, 2) }, \
  53        { DRM_FORMAT_BGRA1010102, DE_VIDEO1 | DE_GRAPHICS1 | DE_VIDEO2, MALIDP_ID(0, 3) }, \
  54        { DRM_FORMAT_ARGB8888, DE_VIDEO1 | DE_GRAPHICS1 | DE_VIDEO2 | DE_SMART, MALIDP_ID(1, 0) }, \
  55        { DRM_FORMAT_ABGR8888, DE_VIDEO1 | DE_GRAPHICS1 | DE_VIDEO2 | DE_SMART, MALIDP_ID(1, 1) }, \
  56        { DRM_FORMAT_RGBA8888, DE_VIDEO1 | DE_GRAPHICS1 | DE_VIDEO2 | DE_SMART, MALIDP_ID(1, 2) }, \
  57        { DRM_FORMAT_BGRA8888, DE_VIDEO1 | DE_GRAPHICS1 | DE_VIDEO2 | DE_SMART, MALIDP_ID(1, 3) }, \
  58        { DRM_FORMAT_XRGB8888, DE_VIDEO1 | DE_GRAPHICS1 | DE_VIDEO2 | DE_SMART, MALIDP_ID(2, 0) }, \
  59        { DRM_FORMAT_XBGR8888, DE_VIDEO1 | DE_GRAPHICS1 | DE_VIDEO2 | DE_SMART, MALIDP_ID(2, 1) }, \
  60        { DRM_FORMAT_RGBX8888, DE_VIDEO1 | DE_GRAPHICS1 | DE_VIDEO2 | DE_SMART, MALIDP_ID(2, 2) }, \
  61        { DRM_FORMAT_BGRX8888, DE_VIDEO1 | DE_GRAPHICS1 | DE_VIDEO2 | DE_SMART, MALIDP_ID(2, 3) }, \
  62        { DRM_FORMAT_RGB888, DE_VIDEO1 | DE_GRAPHICS1 | DE_VIDEO2, MALIDP_ID(3, 0) }, \
  63        { DRM_FORMAT_BGR888, DE_VIDEO1 | DE_GRAPHICS1 | DE_VIDEO2, MALIDP_ID(3, 1) }, \
  64        { DRM_FORMAT_RGBA5551, DE_VIDEO1 | DE_GRAPHICS1 | DE_VIDEO2, MALIDP_ID(4, 0) }, \
  65        { DRM_FORMAT_ABGR1555, DE_VIDEO1 | DE_GRAPHICS1 | DE_VIDEO2, MALIDP_ID(4, 1) }, \
  66        { DRM_FORMAT_RGB565, DE_VIDEO1 | DE_GRAPHICS1 | DE_VIDEO2, MALIDP_ID(4, 2) }, \
  67        { DRM_FORMAT_BGR565, DE_VIDEO1 | DE_GRAPHICS1 | DE_VIDEO2, MALIDP_ID(4, 3) }, \
  68        { DRM_FORMAT_YUYV, DE_VIDEO1 | DE_VIDEO2, MALIDP_ID(5, 2) },    \
  69        { DRM_FORMAT_UYVY, DE_VIDEO1 | DE_VIDEO2, MALIDP_ID(5, 3) },    \
  70        { DRM_FORMAT_NV12, DE_VIDEO1 | DE_VIDEO2, MALIDP_ID(5, 6) },    \
  71        { DRM_FORMAT_YUV420, DE_VIDEO1 | DE_VIDEO2, MALIDP_ID(5, 7) }
  72
  73static const struct malidp_format_id malidp550_de_formats[] = {
  74        MALIDP_COMMON_FORMATS,
  75};
  76
  77static const struct malidp_layer malidp500_layers[] = {
  78        { DE_VIDEO1, MALIDP500_DE_LV_BASE, MALIDP500_DE_LV_PTR_BASE, MALIDP_DE_LV_STRIDE0, MALIDP500_LV_YUV2RGB },
  79        { DE_GRAPHICS1, MALIDP500_DE_LG1_BASE, MALIDP500_DE_LG1_PTR_BASE, MALIDP_DE_LG_STRIDE, 0 },
  80        { DE_GRAPHICS2, MALIDP500_DE_LG2_BASE, MALIDP500_DE_LG2_PTR_BASE, MALIDP_DE_LG_STRIDE, 0 },
  81};
  82
  83static const struct malidp_layer malidp550_layers[] = {
  84        { DE_VIDEO1, MALIDP550_DE_LV1_BASE, MALIDP550_DE_LV1_PTR_BASE, MALIDP_DE_LV_STRIDE0, MALIDP550_LV_YUV2RGB },
  85        { DE_GRAPHICS1, MALIDP550_DE_LG_BASE, MALIDP550_DE_LG_PTR_BASE, MALIDP_DE_LG_STRIDE, 0 },
  86        { DE_VIDEO2, MALIDP550_DE_LV2_BASE, MALIDP550_DE_LV2_PTR_BASE, MALIDP_DE_LV_STRIDE0, MALIDP550_LV_YUV2RGB },
  87        { DE_SMART, MALIDP550_DE_LS_BASE, MALIDP550_DE_LS_PTR_BASE, MALIDP550_DE_LS_R1_STRIDE, 0 },
  88};
  89
  90#define SE_N_SCALING_COEFFS     96
  91static const u16 dp500_se_scaling_coeffs[][SE_N_SCALING_COEFFS] = {
  92        [MALIDP_UPSCALING_COEFFS - 1] = {
  93                0x0000, 0x0001, 0x0007, 0x0011, 0x001e, 0x002e, 0x003f, 0x0052,
  94                0x0064, 0x0073, 0x007d, 0x0080, 0x007a, 0x006c, 0x0053, 0x002f,
  95                0x0000, 0x3fc6, 0x3f83, 0x3f39, 0x3eea, 0x3e9b, 0x3e4f, 0x3e0a,
  96                0x3dd4, 0x3db0, 0x3da2, 0x3db1, 0x3dde, 0x3e2f, 0x3ea5, 0x3f40,
  97                0x0000, 0x00e5, 0x01ee, 0x0315, 0x0456, 0x05aa, 0x0709, 0x086c,
  98                0x09c9, 0x0b15, 0x0c4a, 0x0d5d, 0x0e4a, 0x0f06, 0x0f91, 0x0fe5,
  99                0x1000, 0x0fe5, 0x0f91, 0x0f06, 0x0e4a, 0x0d5d, 0x0c4a, 0x0b15,
 100                0x09c9, 0x086c, 0x0709, 0x05aa, 0x0456, 0x0315, 0x01ee, 0x00e5,
 101                0x0000, 0x3f40, 0x3ea5, 0x3e2f, 0x3dde, 0x3db1, 0x3da2, 0x3db0,
 102                0x3dd4, 0x3e0a, 0x3e4f, 0x3e9b, 0x3eea, 0x3f39, 0x3f83, 0x3fc6,
 103                0x0000, 0x002f, 0x0053, 0x006c, 0x007a, 0x0080, 0x007d, 0x0073,
 104                0x0064, 0x0052, 0x003f, 0x002e, 0x001e, 0x0011, 0x0007, 0x0001
 105        },
 106        [MALIDP_DOWNSCALING_1_5_COEFFS - 1] = {
 107                0x0059, 0x004f, 0x0041, 0x002e, 0x0016, 0x3ffb, 0x3fd9, 0x3fb4,
 108                0x3f8c, 0x3f62, 0x3f36, 0x3f09, 0x3edd, 0x3eb3, 0x3e8d, 0x3e6c,
 109                0x3e52, 0x3e3f, 0x3e35, 0x3e37, 0x3e46, 0x3e61, 0x3e8c, 0x3ec5,
 110                0x3f0f, 0x3f68, 0x3fd1, 0x004a, 0x00d3, 0x0169, 0x020b, 0x02b8,
 111                0x036e, 0x042d, 0x04f2, 0x05b9, 0x0681, 0x0745, 0x0803, 0x08ba,
 112                0x0965, 0x0a03, 0x0a91, 0x0b0d, 0x0b75, 0x0bc6, 0x0c00, 0x0c20,
 113                0x0c28, 0x0c20, 0x0c00, 0x0bc6, 0x0b75, 0x0b0d, 0x0a91, 0x0a03,
 114                0x0965, 0x08ba, 0x0803, 0x0745, 0x0681, 0x05b9, 0x04f2, 0x042d,
 115                0x036e, 0x02b8, 0x020b, 0x0169, 0x00d3, 0x004a, 0x3fd1, 0x3f68,
 116                0x3f0f, 0x3ec5, 0x3e8c, 0x3e61, 0x3e46, 0x3e37, 0x3e35, 0x3e3f,
 117                0x3e52, 0x3e6c, 0x3e8d, 0x3eb3, 0x3edd, 0x3f09, 0x3f36, 0x3f62,
 118                0x3f8c, 0x3fb4, 0x3fd9, 0x3ffb, 0x0016, 0x002e, 0x0041, 0x004f
 119        },
 120        [MALIDP_DOWNSCALING_2_COEFFS - 1] = {
 121                0x3f19, 0x3f03, 0x3ef0, 0x3edf, 0x3ed0, 0x3ec5, 0x3ebd, 0x3eb9,
 122                0x3eb9, 0x3ebf, 0x3eca, 0x3ed9, 0x3eef, 0x3f0a, 0x3f2c, 0x3f52,
 123                0x3f7f, 0x3fb0, 0x3fe8, 0x0026, 0x006a, 0x00b4, 0x0103, 0x0158,
 124                0x01b1, 0x020d, 0x026c, 0x02cd, 0x032f, 0x0392, 0x03f4, 0x0455,
 125                0x04b4, 0x051e, 0x0585, 0x05eb, 0x064c, 0x06a8, 0x06fe, 0x074e,
 126                0x0796, 0x07d5, 0x080c, 0x0839, 0x085c, 0x0875, 0x0882, 0x0887,
 127                0x0881, 0x0887, 0x0882, 0x0875, 0x085c, 0x0839, 0x080c, 0x07d5,
 128                0x0796, 0x074e, 0x06fe, 0x06a8, 0x064c, 0x05eb, 0x0585, 0x051e,
 129                0x04b4, 0x0455, 0x03f4, 0x0392, 0x032f, 0x02cd, 0x026c, 0x020d,
 130                0x01b1, 0x0158, 0x0103, 0x00b4, 0x006a, 0x0026, 0x3fe8, 0x3fb0,
 131                0x3f7f, 0x3f52, 0x3f2c, 0x3f0a, 0x3eef, 0x3ed9, 0x3eca, 0x3ebf,
 132                0x3eb9, 0x3eb9, 0x3ebd, 0x3ec5, 0x3ed0, 0x3edf, 0x3ef0, 0x3f03
 133        },
 134        [MALIDP_DOWNSCALING_2_75_COEFFS - 1] = {
 135                0x3f51, 0x3f60, 0x3f71, 0x3f84, 0x3f98, 0x3faf, 0x3fc8, 0x3fe3,
 136                0x0000, 0x001f, 0x0040, 0x0064, 0x008a, 0x00b1, 0x00da, 0x0106,
 137                0x0133, 0x0160, 0x018e, 0x01bd, 0x01ec, 0x021d, 0x024e, 0x0280,
 138                0x02b2, 0x02e4, 0x0317, 0x0349, 0x037c, 0x03ad, 0x03df, 0x0410,
 139                0x0440, 0x0468, 0x048f, 0x04b3, 0x04d6, 0x04f8, 0x0516, 0x0533,
 140                0x054e, 0x0566, 0x057c, 0x0590, 0x05a0, 0x05ae, 0x05ba, 0x05c3,
 141                0x05c9, 0x05c3, 0x05ba, 0x05ae, 0x05a0, 0x0590, 0x057c, 0x0566,
 142                0x054e, 0x0533, 0x0516, 0x04f8, 0x04d6, 0x04b3, 0x048f, 0x0468,
 143                0x0440, 0x0410, 0x03df, 0x03ad, 0x037c, 0x0349, 0x0317, 0x02e4,
 144                0x02b2, 0x0280, 0x024e, 0x021d, 0x01ec, 0x01bd, 0x018e, 0x0160,
 145                0x0133, 0x0106, 0x00da, 0x00b1, 0x008a, 0x0064, 0x0040, 0x001f,
 146                0x0000, 0x3fe3, 0x3fc8, 0x3faf, 0x3f98, 0x3f84, 0x3f71, 0x3f60
 147        },
 148        [MALIDP_DOWNSCALING_4_COEFFS - 1] = {
 149                0x0094, 0x00a9, 0x00be, 0x00d4, 0x00ea, 0x0101, 0x0118, 0x012f,
 150                0x0148, 0x0160, 0x017a, 0x0193, 0x01ae, 0x01c8, 0x01e4, 0x01ff,
 151                0x021c, 0x0233, 0x024a, 0x0261, 0x0278, 0x028f, 0x02a6, 0x02bd,
 152                0x02d4, 0x02eb, 0x0302, 0x0319, 0x032f, 0x0346, 0x035d, 0x0374,
 153                0x038a, 0x0397, 0x03a3, 0x03af, 0x03bb, 0x03c6, 0x03d1, 0x03db,
 154                0x03e4, 0x03ed, 0x03f6, 0x03fe, 0x0406, 0x040d, 0x0414, 0x041a,
 155                0x0420, 0x041a, 0x0414, 0x040d, 0x0406, 0x03fe, 0x03f6, 0x03ed,
 156                0x03e4, 0x03db, 0x03d1, 0x03c6, 0x03bb, 0x03af, 0x03a3, 0x0397,
 157                0x038a, 0x0374, 0x035d, 0x0346, 0x032f, 0x0319, 0x0302, 0x02eb,
 158                0x02d4, 0x02bd, 0x02a6, 0x028f, 0x0278, 0x0261, 0x024a, 0x0233,
 159                0x021c, 0x01ff, 0x01e4, 0x01c8, 0x01ae, 0x0193, 0x017a, 0x0160,
 160                0x0148, 0x012f, 0x0118, 0x0101, 0x00ea, 0x00d4, 0x00be, 0x00a9
 161        },
 162};
 163
 164#define MALIDP_DE_DEFAULT_PREFETCH_START        5
 165
 166static int malidp500_query_hw(struct malidp_hw_device *hwdev)
 167{
 168        u32 conf = malidp_hw_read(hwdev, MALIDP500_CONFIG_ID);
 169        /* bit 4 of the CONFIG_ID register holds the line size multiplier */
 170        u8 ln_size_mult = conf & 0x10 ? 2 : 1;
 171
 172        hwdev->min_line_size = 2;
 173        hwdev->max_line_size = SZ_2K * ln_size_mult;
 174        hwdev->rotation_memory[0] = SZ_1K * 64 * ln_size_mult;
 175        hwdev->rotation_memory[1] = 0; /* no second rotation memory bank */
 176
 177        return 0;
 178}
 179
 180static void malidp500_enter_config_mode(struct malidp_hw_device *hwdev)
 181{
 182        u32 status, count = 100;
 183
 184        malidp_hw_setbits(hwdev, MALIDP500_DC_CONFIG_REQ, MALIDP500_DC_CONTROL);
 185        while (count) {
 186                status = malidp_hw_read(hwdev, hwdev->hw->map.dc_base + MALIDP_REG_STATUS);
 187                if ((status & MALIDP500_DC_CONFIG_REQ) == MALIDP500_DC_CONFIG_REQ)
 188                        break;
 189                /*
 190                 * entering config mode can take as long as the rendering
 191                 * of a full frame, hence the long sleep here
 192                 */
 193                usleep_range(1000, 10000);
 194                count--;
 195        }
 196        WARN(count == 0, "timeout while entering config mode");
 197}
 198
 199static void malidp500_leave_config_mode(struct malidp_hw_device *hwdev)
 200{
 201        u32 status, count = 100;
 202
 203        malidp_hw_clearbits(hwdev, MALIDP_CFG_VALID, MALIDP500_CONFIG_VALID);
 204        malidp_hw_clearbits(hwdev, MALIDP500_DC_CONFIG_REQ, MALIDP500_DC_CONTROL);
 205        while (count) {
 206                status = malidp_hw_read(hwdev, hwdev->hw->map.dc_base + MALIDP_REG_STATUS);
 207                if ((status & MALIDP500_DC_CONFIG_REQ) == 0)
 208                        break;
 209                usleep_range(100, 1000);
 210                count--;
 211        }
 212        WARN(count == 0, "timeout while leaving config mode");
 213}
 214
 215static bool malidp500_in_config_mode(struct malidp_hw_device *hwdev)
 216{
 217        u32 status;
 218
 219        status = malidp_hw_read(hwdev, hwdev->hw->map.dc_base + MALIDP_REG_STATUS);
 220        if ((status & MALIDP500_DC_CONFIG_REQ) == MALIDP500_DC_CONFIG_REQ)
 221                return true;
 222
 223        return false;
 224}
 225
 226static void malidp500_set_config_valid(struct malidp_hw_device *hwdev)
 227{
 228        malidp_hw_setbits(hwdev, MALIDP_CFG_VALID, MALIDP500_CONFIG_VALID);
 229}
 230
 231static void malidp500_modeset(struct malidp_hw_device *hwdev, struct videomode *mode)
 232{
 233        u32 val = 0;
 234
 235        malidp_hw_clearbits(hwdev, MALIDP500_DC_CLEAR_MASK, MALIDP500_DC_CONTROL);
 236        if (mode->flags & DISPLAY_FLAGS_HSYNC_HIGH)
 237                val |= MALIDP500_HSYNCPOL;
 238        if (mode->flags & DISPLAY_FLAGS_VSYNC_HIGH)
 239                val |= MALIDP500_VSYNCPOL;
 240        val |= MALIDP_DE_DEFAULT_PREFETCH_START;
 241        malidp_hw_setbits(hwdev, val, MALIDP500_DC_CONTROL);
 242
 243        /*
 244         * Mali-DP500 encodes the background color like this:
 245         *    - red   @ MALIDP500_BGND_COLOR[12:0]
 246         *    - green @ MALIDP500_BGND_COLOR[27:16]
 247         *    - blue  @ (MALIDP500_BGND_COLOR + 4)[12:0]
 248         */
 249        val = ((MALIDP_BGND_COLOR_G & 0xfff) << 16) |
 250              (MALIDP_BGND_COLOR_R & 0xfff);
 251        malidp_hw_write(hwdev, val, MALIDP500_BGND_COLOR);
 252        malidp_hw_write(hwdev, MALIDP_BGND_COLOR_B, MALIDP500_BGND_COLOR + 4);
 253
 254        val = MALIDP_DE_H_FRONTPORCH(mode->hfront_porch) |
 255                MALIDP_DE_H_BACKPORCH(mode->hback_porch);
 256        malidp_hw_write(hwdev, val, MALIDP500_TIMINGS_BASE + MALIDP_DE_H_TIMINGS);
 257
 258        val = MALIDP500_DE_V_FRONTPORCH(mode->vfront_porch) |
 259                MALIDP_DE_V_BACKPORCH(mode->vback_porch);
 260        malidp_hw_write(hwdev, val, MALIDP500_TIMINGS_BASE + MALIDP_DE_V_TIMINGS);
 261
 262        val = MALIDP_DE_H_SYNCWIDTH(mode->hsync_len) |
 263                MALIDP_DE_V_SYNCWIDTH(mode->vsync_len);
 264        malidp_hw_write(hwdev, val, MALIDP500_TIMINGS_BASE + MALIDP_DE_SYNC_WIDTH);
 265
 266        val = MALIDP_DE_H_ACTIVE(mode->hactive) | MALIDP_DE_V_ACTIVE(mode->vactive);
 267        malidp_hw_write(hwdev, val, MALIDP500_TIMINGS_BASE + MALIDP_DE_HV_ACTIVE);
 268
 269        if (mode->flags & DISPLAY_FLAGS_INTERLACED)
 270                malidp_hw_setbits(hwdev, MALIDP_DISP_FUNC_ILACED, MALIDP_DE_DISPLAY_FUNC);
 271        else
 272                malidp_hw_clearbits(hwdev, MALIDP_DISP_FUNC_ILACED, MALIDP_DE_DISPLAY_FUNC);
 273}
 274
 275static int malidp500_rotmem_required(struct malidp_hw_device *hwdev, u16 w, u16 h, u32 fmt)
 276{
 277        /* RGB888 or BGR888 can't be rotated */
 278        if ((fmt == DRM_FORMAT_RGB888) || (fmt == DRM_FORMAT_BGR888))
 279                return -EINVAL;
 280
 281        /*
 282         * Each layer needs enough rotation memory to fit 8 lines
 283         * worth of pixel data. Required size is then:
 284         *    size = rotated_width * (bpp / 8) * 8;
 285         */
 286        return w * drm_format_plane_cpp(fmt, 0) * 8;
 287}
 288
 289static void malidp500_se_write_pp_coefftab(struct malidp_hw_device *hwdev,
 290                                           u32 direction,
 291                                           u16 addr,
 292                                           u8 coeffs_id)
 293{
 294        int i;
 295        u16 scaling_control = MALIDP500_SE_CONTROL + MALIDP_SE_SCALING_CONTROL;
 296
 297        malidp_hw_write(hwdev,
 298                        direction | (addr & MALIDP_SE_COEFFTAB_ADDR_MASK),
 299                        scaling_control + MALIDP_SE_COEFFTAB_ADDR);
 300        for (i = 0; i < ARRAY_SIZE(dp500_se_scaling_coeffs); ++i)
 301                malidp_hw_write(hwdev, MALIDP_SE_SET_COEFFTAB_DATA(
 302                                dp500_se_scaling_coeffs[coeffs_id][i]),
 303                                scaling_control + MALIDP_SE_COEFFTAB_DATA);
 304}
 305
 306static int malidp500_se_set_scaling_coeffs(struct malidp_hw_device *hwdev,
 307                                           struct malidp_se_config *se_config,
 308                                           struct malidp_se_config *old_config)
 309{
 310        /* Get array indices into dp500_se_scaling_coeffs. */
 311        u8 h = (u8)se_config->hcoeff - 1;
 312        u8 v = (u8)se_config->vcoeff - 1;
 313
 314        if (WARN_ON(h >= ARRAY_SIZE(dp500_se_scaling_coeffs) ||
 315                    v >= ARRAY_SIZE(dp500_se_scaling_coeffs)))
 316                return -EINVAL;
 317
 318        if ((h == v) && (se_config->hcoeff != old_config->hcoeff ||
 319                         se_config->vcoeff != old_config->vcoeff)) {
 320                malidp500_se_write_pp_coefftab(hwdev,
 321                                               (MALIDP_SE_V_COEFFTAB |
 322                                                MALIDP_SE_H_COEFFTAB),
 323                                               0, v);
 324        } else {
 325                if (se_config->vcoeff != old_config->vcoeff)
 326                        malidp500_se_write_pp_coefftab(hwdev,
 327                                                       MALIDP_SE_V_COEFFTAB,
 328                                                       0, v);
 329                if (se_config->hcoeff != old_config->hcoeff)
 330                        malidp500_se_write_pp_coefftab(hwdev,
 331                                                       MALIDP_SE_H_COEFFTAB,
 332                                                       0, h);
 333        }
 334
 335        return 0;
 336}
 337
 338static long malidp500_se_calc_mclk(struct malidp_hw_device *hwdev,
 339                                   struct malidp_se_config *se_config,
 340                                   struct videomode *vm)
 341{
 342        unsigned long mclk;
 343        unsigned long pxlclk = vm->pixelclock; /* Hz */
 344        unsigned long htotal = vm->hactive + vm->hfront_porch +
 345                               vm->hback_porch + vm->hsync_len;
 346        unsigned long input_size = se_config->input_w * se_config->input_h;
 347        unsigned long a = 10;
 348        long ret;
 349
 350        /*
 351         * mclk = max(a, 1.5) * pxlclk
 352         *
 353         * To avoid float calculaiton, using 15 instead of 1.5 and div by
 354         * 10 to get mclk.
 355         */
 356        if (se_config->scale_enable) {
 357                a = 15 * input_size / (htotal * se_config->output_h);
 358                if (a < 15)
 359                        a = 15;
 360        }
 361        mclk = a * pxlclk / 10;
 362        ret = clk_get_rate(hwdev->mclk);
 363        if (ret < mclk) {
 364                DRM_DEBUG_DRIVER("mclk requirement of %lu kHz can't be met.\n",
 365                                 mclk / 1000);
 366                return -EINVAL;
 367        }
 368        return ret;
 369}
 370
 371static int malidp550_query_hw(struct malidp_hw_device *hwdev)
 372{
 373        u32 conf = malidp_hw_read(hwdev, MALIDP550_CONFIG_ID);
 374        u8 ln_size = (conf >> 4) & 0x3, rsize;
 375
 376        hwdev->min_line_size = 2;
 377
 378        switch (ln_size) {
 379        case 0:
 380                hwdev->max_line_size = SZ_2K;
 381                /* two banks of 64KB for rotation memory */
 382                rsize = 64;
 383                break;
 384        case 1:
 385                hwdev->max_line_size = SZ_4K;
 386                /* two banks of 128KB for rotation memory */
 387                rsize = 128;
 388                break;
 389        case 2:
 390                hwdev->max_line_size = 1280;
 391                /* two banks of 40KB for rotation memory */
 392                rsize = 40;
 393                break;
 394        case 3:
 395                /* reserved value */
 396                hwdev->max_line_size = 0;
 397                return -EINVAL;
 398        }
 399
 400        hwdev->rotation_memory[0] = hwdev->rotation_memory[1] = rsize * SZ_1K;
 401        return 0;
 402}
 403
 404static void malidp550_enter_config_mode(struct malidp_hw_device *hwdev)
 405{
 406        u32 status, count = 100;
 407
 408        malidp_hw_setbits(hwdev, MALIDP550_DC_CONFIG_REQ, MALIDP550_DC_CONTROL);
 409        while (count) {
 410                status = malidp_hw_read(hwdev, hwdev->hw->map.dc_base + MALIDP_REG_STATUS);
 411                if ((status & MALIDP550_DC_CONFIG_REQ) == MALIDP550_DC_CONFIG_REQ)
 412                        break;
 413                /*
 414                 * entering config mode can take as long as the rendering
 415                 * of a full frame, hence the long sleep here
 416                 */
 417                usleep_range(1000, 10000);
 418                count--;
 419        }
 420        WARN(count == 0, "timeout while entering config mode");
 421}
 422
 423static void malidp550_leave_config_mode(struct malidp_hw_device *hwdev)
 424{
 425        u32 status, count = 100;
 426
 427        malidp_hw_clearbits(hwdev, MALIDP_CFG_VALID, MALIDP550_CONFIG_VALID);
 428        malidp_hw_clearbits(hwdev, MALIDP550_DC_CONFIG_REQ, MALIDP550_DC_CONTROL);
 429        while (count) {
 430                status = malidp_hw_read(hwdev, hwdev->hw->map.dc_base + MALIDP_REG_STATUS);
 431                if ((status & MALIDP550_DC_CONFIG_REQ) == 0)
 432                        break;
 433                usleep_range(100, 1000);
 434                count--;
 435        }
 436        WARN(count == 0, "timeout while leaving config mode");
 437}
 438
 439static bool malidp550_in_config_mode(struct malidp_hw_device *hwdev)
 440{
 441        u32 status;
 442
 443        status = malidp_hw_read(hwdev, hwdev->hw->map.dc_base + MALIDP_REG_STATUS);
 444        if ((status & MALIDP550_DC_CONFIG_REQ) == MALIDP550_DC_CONFIG_REQ)
 445                return true;
 446
 447        return false;
 448}
 449
 450static void malidp550_set_config_valid(struct malidp_hw_device *hwdev)
 451{
 452        malidp_hw_setbits(hwdev, MALIDP_CFG_VALID, MALIDP550_CONFIG_VALID);
 453}
 454
 455static void malidp550_modeset(struct malidp_hw_device *hwdev, struct videomode *mode)
 456{
 457        u32 val = MALIDP_DE_DEFAULT_PREFETCH_START;
 458
 459        malidp_hw_write(hwdev, val, MALIDP550_DE_CONTROL);
 460        /*
 461         * Mali-DP550 and Mali-DP650 encode the background color like this:
 462         *   - red   @ MALIDP550_DE_BGND_COLOR[23:16]
 463         *   - green @ MALIDP550_DE_BGND_COLOR[15:8]
 464         *   - blue  @ MALIDP550_DE_BGND_COLOR[7:0]
 465         *
 466         * We need to truncate the least significant 4 bits from the default
 467         * MALIDP_BGND_COLOR_x values
 468         */
 469        val = (((MALIDP_BGND_COLOR_R >> 4) & 0xff) << 16) |
 470              (((MALIDP_BGND_COLOR_G >> 4) & 0xff) << 8) |
 471              ((MALIDP_BGND_COLOR_B >> 4) & 0xff);
 472        malidp_hw_write(hwdev, val, MALIDP550_DE_BGND_COLOR);
 473
 474        val = MALIDP_DE_H_FRONTPORCH(mode->hfront_porch) |
 475                MALIDP_DE_H_BACKPORCH(mode->hback_porch);
 476        malidp_hw_write(hwdev, val, MALIDP550_TIMINGS_BASE + MALIDP_DE_H_TIMINGS);
 477
 478        val = MALIDP550_DE_V_FRONTPORCH(mode->vfront_porch) |
 479                MALIDP_DE_V_BACKPORCH(mode->vback_porch);
 480        malidp_hw_write(hwdev, val, MALIDP550_TIMINGS_BASE + MALIDP_DE_V_TIMINGS);
 481
 482        val = MALIDP_DE_H_SYNCWIDTH(mode->hsync_len) |
 483                MALIDP_DE_V_SYNCWIDTH(mode->vsync_len);
 484        if (mode->flags & DISPLAY_FLAGS_HSYNC_HIGH)
 485                val |= MALIDP550_HSYNCPOL;
 486        if (mode->flags & DISPLAY_FLAGS_VSYNC_HIGH)
 487                val |= MALIDP550_VSYNCPOL;
 488        malidp_hw_write(hwdev, val, MALIDP550_TIMINGS_BASE + MALIDP_DE_SYNC_WIDTH);
 489
 490        val = MALIDP_DE_H_ACTIVE(mode->hactive) | MALIDP_DE_V_ACTIVE(mode->vactive);
 491        malidp_hw_write(hwdev, val, MALIDP550_TIMINGS_BASE + MALIDP_DE_HV_ACTIVE);
 492
 493        if (mode->flags & DISPLAY_FLAGS_INTERLACED)
 494                malidp_hw_setbits(hwdev, MALIDP_DISP_FUNC_ILACED, MALIDP_DE_DISPLAY_FUNC);
 495        else
 496                malidp_hw_clearbits(hwdev, MALIDP_DISP_FUNC_ILACED, MALIDP_DE_DISPLAY_FUNC);
 497}
 498
 499static int malidp550_rotmem_required(struct malidp_hw_device *hwdev, u16 w, u16 h, u32 fmt)
 500{
 501        u32 bytes_per_col;
 502
 503        /* raw RGB888 or BGR888 can't be rotated */
 504        if ((fmt == DRM_FORMAT_RGB888) || (fmt == DRM_FORMAT_BGR888))
 505                return -EINVAL;
 506
 507        switch (fmt) {
 508        /* 8 lines at 4 bytes per pixel */
 509        case DRM_FORMAT_ARGB2101010:
 510        case DRM_FORMAT_ABGR2101010:
 511        case DRM_FORMAT_RGBA1010102:
 512        case DRM_FORMAT_BGRA1010102:
 513        case DRM_FORMAT_ARGB8888:
 514        case DRM_FORMAT_ABGR8888:
 515        case DRM_FORMAT_RGBA8888:
 516        case DRM_FORMAT_BGRA8888:
 517        case DRM_FORMAT_XRGB8888:
 518        case DRM_FORMAT_XBGR8888:
 519        case DRM_FORMAT_RGBX8888:
 520        case DRM_FORMAT_BGRX8888:
 521        case DRM_FORMAT_RGB888:
 522        case DRM_FORMAT_BGR888:
 523        /* 16 lines at 2 bytes per pixel */
 524        case DRM_FORMAT_RGBA5551:
 525        case DRM_FORMAT_ABGR1555:
 526        case DRM_FORMAT_RGB565:
 527        case DRM_FORMAT_BGR565:
 528        case DRM_FORMAT_UYVY:
 529        case DRM_FORMAT_YUYV:
 530                bytes_per_col = 32;
 531                break;
 532        /* 16 lines at 1.5 bytes per pixel */
 533        case DRM_FORMAT_NV12:
 534        case DRM_FORMAT_YUV420:
 535                bytes_per_col = 24;
 536                break;
 537        default:
 538                return -EINVAL;
 539        }
 540
 541        return w * bytes_per_col;
 542}
 543
 544static int malidp550_se_set_scaling_coeffs(struct malidp_hw_device *hwdev,
 545                                           struct malidp_se_config *se_config,
 546                                           struct malidp_se_config *old_config)
 547{
 548        u32 mask = MALIDP550_SE_CTL_VCSEL(MALIDP550_SE_CTL_SEL_MASK) |
 549                   MALIDP550_SE_CTL_HCSEL(MALIDP550_SE_CTL_SEL_MASK);
 550        u32 new_value = MALIDP550_SE_CTL_VCSEL(se_config->vcoeff) |
 551                        MALIDP550_SE_CTL_HCSEL(se_config->hcoeff);
 552
 553        malidp_hw_clearbits(hwdev, mask, MALIDP550_SE_CONTROL);
 554        malidp_hw_setbits(hwdev, new_value, MALIDP550_SE_CONTROL);
 555        return 0;
 556}
 557
 558static long malidp550_se_calc_mclk(struct malidp_hw_device *hwdev,
 559                                   struct malidp_se_config *se_config,
 560                                   struct videomode *vm)
 561{
 562        unsigned long mclk;
 563        unsigned long pxlclk = vm->pixelclock;
 564        unsigned long htotal = vm->hactive + vm->hfront_porch +
 565                               vm->hback_porch + vm->hsync_len;
 566        unsigned long numerator = 1, denominator = 1;
 567        long ret;
 568
 569        if (se_config->scale_enable) {
 570                numerator = max(se_config->input_w, se_config->output_w) *
 571                            se_config->input_h;
 572                numerator += se_config->output_w *
 573                             (se_config->output_h -
 574                              min(se_config->input_h, se_config->output_h));
 575                denominator = (htotal - 2) * se_config->output_h;
 576        }
 577
 578        /* mclk can't be slower than pxlclk. */
 579        if (numerator < denominator)
 580                numerator = denominator = 1;
 581        mclk = (pxlclk * numerator) / denominator;
 582        ret = clk_get_rate(hwdev->mclk);
 583        if (ret < mclk) {
 584                DRM_DEBUG_DRIVER("mclk requirement of %lu kHz can't be met.\n",
 585                                 mclk / 1000);
 586                return -EINVAL;
 587        }
 588        return ret;
 589}
 590
 591static int malidp650_query_hw(struct malidp_hw_device *hwdev)
 592{
 593        u32 conf = malidp_hw_read(hwdev, MALIDP550_CONFIG_ID);
 594        u8 ln_size = (conf >> 4) & 0x3, rsize;
 595
 596        hwdev->min_line_size = 4;
 597
 598        switch (ln_size) {
 599        case 0:
 600        case 2:
 601                /* reserved values */
 602                hwdev->max_line_size = 0;
 603                return -EINVAL;
 604        case 1:
 605                hwdev->max_line_size = SZ_4K;
 606                /* two banks of 128KB for rotation memory */
 607                rsize = 128;
 608                break;
 609        case 3:
 610                hwdev->max_line_size = 2560;
 611                /* two banks of 80KB for rotation memory */
 612                rsize = 80;
 613        }
 614
 615        hwdev->rotation_memory[0] = hwdev->rotation_memory[1] = rsize * SZ_1K;
 616        return 0;
 617}
 618
 619const struct malidp_hw malidp_device[MALIDP_MAX_DEVICES] = {
 620        [MALIDP_500] = {
 621                .map = {
 622                        .coeffs_base = MALIDP500_COEFFS_BASE,
 623                        .se_base = MALIDP500_SE_BASE,
 624                        .dc_base = MALIDP500_DC_BASE,
 625                        .out_depth_base = MALIDP500_OUTPUT_DEPTH,
 626                        .features = 0,  /* no CLEARIRQ register */
 627                        .n_layers = ARRAY_SIZE(malidp500_layers),
 628                        .layers = malidp500_layers,
 629                        .de_irq_map = {
 630                                .irq_mask = MALIDP_DE_IRQ_UNDERRUN |
 631                                            MALIDP500_DE_IRQ_AXI_ERR |
 632                                            MALIDP500_DE_IRQ_VSYNC |
 633                                            MALIDP500_DE_IRQ_GLOBAL,
 634                                .vsync_irq = MALIDP500_DE_IRQ_VSYNC,
 635                        },
 636                        .se_irq_map = {
 637                                .irq_mask = MALIDP500_SE_IRQ_CONF_MODE,
 638                                .vsync_irq = 0,
 639                        },
 640                        .dc_irq_map = {
 641                                .irq_mask = MALIDP500_DE_IRQ_CONF_VALID,
 642                                .vsync_irq = MALIDP500_DE_IRQ_CONF_VALID,
 643                        },
 644                        .pixel_formats = malidp500_de_formats,
 645                        .n_pixel_formats = ARRAY_SIZE(malidp500_de_formats),
 646                        .bus_align_bytes = 8,
 647                },
 648                .query_hw = malidp500_query_hw,
 649                .enter_config_mode = malidp500_enter_config_mode,
 650                .leave_config_mode = malidp500_leave_config_mode,
 651                .in_config_mode = malidp500_in_config_mode,
 652                .set_config_valid = malidp500_set_config_valid,
 653                .modeset = malidp500_modeset,
 654                .rotmem_required = malidp500_rotmem_required,
 655                .se_set_scaling_coeffs = malidp500_se_set_scaling_coeffs,
 656                .se_calc_mclk = malidp500_se_calc_mclk,
 657                .features = MALIDP_DEVICE_LV_HAS_3_STRIDES,
 658        },
 659        [MALIDP_550] = {
 660                .map = {
 661                        .coeffs_base = MALIDP550_COEFFS_BASE,
 662                        .se_base = MALIDP550_SE_BASE,
 663                        .dc_base = MALIDP550_DC_BASE,
 664                        .out_depth_base = MALIDP550_DE_OUTPUT_DEPTH,
 665                        .features = MALIDP_REGMAP_HAS_CLEARIRQ,
 666                        .n_layers = ARRAY_SIZE(malidp550_layers),
 667                        .layers = malidp550_layers,
 668                        .de_irq_map = {
 669                                .irq_mask = MALIDP_DE_IRQ_UNDERRUN |
 670                                            MALIDP550_DE_IRQ_VSYNC,
 671                                .vsync_irq = MALIDP550_DE_IRQ_VSYNC,
 672                        },
 673                        .se_irq_map = {
 674                                .irq_mask = MALIDP550_SE_IRQ_EOW |
 675                                            MALIDP550_SE_IRQ_AXI_ERR,
 676                        },
 677                        .dc_irq_map = {
 678                                .irq_mask = MALIDP550_DC_IRQ_CONF_VALID,
 679                                .vsync_irq = MALIDP550_DC_IRQ_CONF_VALID,
 680                        },
 681                        .pixel_formats = malidp550_de_formats,
 682                        .n_pixel_formats = ARRAY_SIZE(malidp550_de_formats),
 683                        .bus_align_bytes = 8,
 684                },
 685                .query_hw = malidp550_query_hw,
 686                .enter_config_mode = malidp550_enter_config_mode,
 687                .leave_config_mode = malidp550_leave_config_mode,
 688                .in_config_mode = malidp550_in_config_mode,
 689                .set_config_valid = malidp550_set_config_valid,
 690                .modeset = malidp550_modeset,
 691                .rotmem_required = malidp550_rotmem_required,
 692                .se_set_scaling_coeffs = malidp550_se_set_scaling_coeffs,
 693                .se_calc_mclk = malidp550_se_calc_mclk,
 694                .features = 0,
 695        },
 696        [MALIDP_650] = {
 697                .map = {
 698                        .coeffs_base = MALIDP550_COEFFS_BASE,
 699                        .se_base = MALIDP550_SE_BASE,
 700                        .dc_base = MALIDP550_DC_BASE,
 701                        .out_depth_base = MALIDP550_DE_OUTPUT_DEPTH,
 702                        .features = MALIDP_REGMAP_HAS_CLEARIRQ,
 703                        .n_layers = ARRAY_SIZE(malidp550_layers),
 704                        .layers = malidp550_layers,
 705                        .de_irq_map = {
 706                                .irq_mask = MALIDP_DE_IRQ_UNDERRUN |
 707                                            MALIDP650_DE_IRQ_DRIFT |
 708                                            MALIDP550_DE_IRQ_VSYNC,
 709                                .vsync_irq = MALIDP550_DE_IRQ_VSYNC,
 710                        },
 711                        .se_irq_map = {
 712                                .irq_mask = MALIDP550_SE_IRQ_EOW |
 713                                            MALIDP550_SE_IRQ_AXI_ERR,
 714                        },
 715                        .dc_irq_map = {
 716                                .irq_mask = MALIDP550_DC_IRQ_CONF_VALID,
 717                                .vsync_irq = MALIDP550_DC_IRQ_CONF_VALID,
 718                        },
 719                        .pixel_formats = malidp550_de_formats,
 720                        .n_pixel_formats = ARRAY_SIZE(malidp550_de_formats),
 721                        .bus_align_bytes = 16,
 722                },
 723                .query_hw = malidp650_query_hw,
 724                .enter_config_mode = malidp550_enter_config_mode,
 725                .leave_config_mode = malidp550_leave_config_mode,
 726                .in_config_mode = malidp550_in_config_mode,
 727                .set_config_valid = malidp550_set_config_valid,
 728                .modeset = malidp550_modeset,
 729                .rotmem_required = malidp550_rotmem_required,
 730                .se_set_scaling_coeffs = malidp550_se_set_scaling_coeffs,
 731                .se_calc_mclk = malidp550_se_calc_mclk,
 732                .features = 0,
 733        },
 734};
 735
 736u8 malidp_hw_get_format_id(const struct malidp_hw_regmap *map,
 737                           u8 layer_id, u32 format)
 738{
 739        unsigned int i;
 740
 741        for (i = 0; i < map->n_pixel_formats; i++) {
 742                if (((map->pixel_formats[i].layer & layer_id) == layer_id) &&
 743                    (map->pixel_formats[i].format == format))
 744                        return map->pixel_formats[i].id;
 745        }
 746
 747        return MALIDP_INVALID_FORMAT_ID;
 748}
 749
 750static void malidp_hw_clear_irq(struct malidp_hw_device *hwdev, u8 block, u32 irq)
 751{
 752        u32 base = malidp_get_block_base(hwdev, block);
 753
 754        if (hwdev->hw->map.features & MALIDP_REGMAP_HAS_CLEARIRQ)
 755                malidp_hw_write(hwdev, irq, base + MALIDP_REG_CLEARIRQ);
 756        else
 757                malidp_hw_write(hwdev, irq, base + MALIDP_REG_STATUS);
 758}
 759
 760static irqreturn_t malidp_de_irq(int irq, void *arg)
 761{
 762        struct drm_device *drm = arg;
 763        struct malidp_drm *malidp = drm->dev_private;
 764        struct malidp_hw_device *hwdev;
 765        struct malidp_hw *hw;
 766        const struct malidp_irq_map *de;
 767        u32 status, mask, dc_status;
 768        irqreturn_t ret = IRQ_NONE;
 769
 770        hwdev = malidp->dev;
 771        hw = hwdev->hw;
 772        de = &hw->map.de_irq_map;
 773
 774        /*
 775         * if we are suspended it is likely that we were invoked because
 776         * we share an interrupt line with some other driver, don't try
 777         * to read the hardware registers
 778         */
 779        if (hwdev->pm_suspended)
 780                return IRQ_NONE;
 781
 782        /* first handle the config valid IRQ */
 783        dc_status = malidp_hw_read(hwdev, hw->map.dc_base + MALIDP_REG_STATUS);
 784        if (dc_status & hw->map.dc_irq_map.vsync_irq) {
 785                malidp_hw_clear_irq(hwdev, MALIDP_DC_BLOCK, dc_status);
 786                /* do we have a page flip event? */
 787                if (malidp->event != NULL) {
 788                        spin_lock(&drm->event_lock);
 789                        drm_crtc_send_vblank_event(&malidp->crtc, malidp->event);
 790                        malidp->event = NULL;
 791                        spin_unlock(&drm->event_lock);
 792                }
 793                atomic_set(&malidp->config_valid, 1);
 794                ret = IRQ_WAKE_THREAD;
 795        }
 796
 797        status = malidp_hw_read(hwdev, MALIDP_REG_STATUS);
 798        if (!(status & de->irq_mask))
 799                return ret;
 800
 801        mask = malidp_hw_read(hwdev, MALIDP_REG_MASKIRQ);
 802        status &= mask;
 803        if ((status & de->vsync_irq) && malidp->crtc.enabled)
 804                drm_crtc_handle_vblank(&malidp->crtc);
 805
 806        malidp_hw_clear_irq(hwdev, MALIDP_DE_BLOCK, status);
 807
 808        return (ret == IRQ_NONE) ? IRQ_HANDLED : ret;
 809}
 810
 811static irqreturn_t malidp_de_irq_thread_handler(int irq, void *arg)
 812{
 813        struct drm_device *drm = arg;
 814        struct malidp_drm *malidp = drm->dev_private;
 815
 816        wake_up(&malidp->wq);
 817
 818        return IRQ_HANDLED;
 819}
 820
 821int malidp_de_irq_init(struct drm_device *drm, int irq)
 822{
 823        struct malidp_drm *malidp = drm->dev_private;
 824        struct malidp_hw_device *hwdev = malidp->dev;
 825        int ret;
 826
 827        /* ensure interrupts are disabled */
 828        malidp_hw_disable_irq(hwdev, MALIDP_DE_BLOCK, 0xffffffff);
 829        malidp_hw_clear_irq(hwdev, MALIDP_DE_BLOCK, 0xffffffff);
 830        malidp_hw_disable_irq(hwdev, MALIDP_DC_BLOCK, 0xffffffff);
 831        malidp_hw_clear_irq(hwdev, MALIDP_DC_BLOCK, 0xffffffff);
 832
 833        ret = devm_request_threaded_irq(drm->dev, irq, malidp_de_irq,
 834                                        malidp_de_irq_thread_handler,
 835                                        IRQF_SHARED, "malidp-de", drm);
 836        if (ret < 0) {
 837                DRM_ERROR("failed to install DE IRQ handler\n");
 838                return ret;
 839        }
 840
 841        /* first enable the DC block IRQs */
 842        malidp_hw_enable_irq(hwdev, MALIDP_DC_BLOCK,
 843                             hwdev->hw->map.dc_irq_map.irq_mask);
 844
 845        /* now enable the DE block IRQs */
 846        malidp_hw_enable_irq(hwdev, MALIDP_DE_BLOCK,
 847                             hwdev->hw->map.de_irq_map.irq_mask);
 848
 849        return 0;
 850}
 851
 852void malidp_de_irq_fini(struct drm_device *drm)
 853{
 854        struct malidp_drm *malidp = drm->dev_private;
 855        struct malidp_hw_device *hwdev = malidp->dev;
 856
 857        malidp_hw_disable_irq(hwdev, MALIDP_DE_BLOCK,
 858                              hwdev->hw->map.de_irq_map.irq_mask);
 859        malidp_hw_disable_irq(hwdev, MALIDP_DC_BLOCK,
 860                              hwdev->hw->map.dc_irq_map.irq_mask);
 861}
 862
 863static irqreturn_t malidp_se_irq(int irq, void *arg)
 864{
 865        struct drm_device *drm = arg;
 866        struct malidp_drm *malidp = drm->dev_private;
 867        struct malidp_hw_device *hwdev = malidp->dev;
 868        struct malidp_hw *hw = hwdev->hw;
 869        const struct malidp_irq_map *se = &hw->map.se_irq_map;
 870        u32 status, mask;
 871
 872        /*
 873         * if we are suspended it is likely that we were invoked because
 874         * we share an interrupt line with some other driver, don't try
 875         * to read the hardware registers
 876         */
 877        if (hwdev->pm_suspended)
 878                return IRQ_NONE;
 879
 880        status = malidp_hw_read(hwdev, hw->map.se_base + MALIDP_REG_STATUS);
 881        if (!(status & se->irq_mask))
 882                return IRQ_NONE;
 883
 884        mask = malidp_hw_read(hwdev, hw->map.se_base + MALIDP_REG_MASKIRQ);
 885        status = malidp_hw_read(hwdev, hw->map.se_base + MALIDP_REG_STATUS);
 886        status &= mask;
 887        /* ToDo: status decoding and firing up of VSYNC and page flip events */
 888
 889        malidp_hw_clear_irq(hwdev, MALIDP_SE_BLOCK, status);
 890
 891        return IRQ_HANDLED;
 892}
 893
 894static irqreturn_t malidp_se_irq_thread_handler(int irq, void *arg)
 895{
 896        return IRQ_HANDLED;
 897}
 898
 899int malidp_se_irq_init(struct drm_device *drm, int irq)
 900{
 901        struct malidp_drm *malidp = drm->dev_private;
 902        struct malidp_hw_device *hwdev = malidp->dev;
 903        int ret;
 904
 905        /* ensure interrupts are disabled */
 906        malidp_hw_disable_irq(hwdev, MALIDP_SE_BLOCK, 0xffffffff);
 907        malidp_hw_clear_irq(hwdev, MALIDP_SE_BLOCK, 0xffffffff);
 908
 909        ret = devm_request_threaded_irq(drm->dev, irq, malidp_se_irq,
 910                                        malidp_se_irq_thread_handler,
 911                                        IRQF_SHARED, "malidp-se", drm);
 912        if (ret < 0) {
 913                DRM_ERROR("failed to install SE IRQ handler\n");
 914                return ret;
 915        }
 916
 917        malidp_hw_enable_irq(hwdev, MALIDP_SE_BLOCK,
 918                             hwdev->hw->map.se_irq_map.irq_mask);
 919
 920        return 0;
 921}
 922
 923void malidp_se_irq_fini(struct drm_device *drm)
 924{
 925        struct malidp_drm *malidp = drm->dev_private;
 926        struct malidp_hw_device *hwdev = malidp->dev;
 927
 928        malidp_hw_disable_irq(hwdev, MALIDP_SE_BLOCK,
 929                              hwdev->hw->map.se_irq_map.irq_mask);
 930}
 931