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#include "malidp_mw.h"
  25
  26enum {
  27        MW_NOT_ENABLED = 0,     /* SE writeback not enabled */
  28        MW_ONESHOT,             /* SE in one-shot mode for writeback */
  29        MW_START,               /* SE started writeback */
  30        MW_RESTART,             /* SE will start another writeback after this one */
  31        MW_STOP,                /* SE needs to stop after this writeback */
  32};
  33
  34static const struct malidp_format_id malidp500_de_formats[] = {
  35        /*    fourcc,   layers supporting the format,     internal id  */
  36        { DRM_FORMAT_ARGB2101010, DE_VIDEO1 | DE_GRAPHICS1 | DE_GRAPHICS2 | SE_MEMWRITE,  0 },
  37        { DRM_FORMAT_ABGR2101010, DE_VIDEO1 | DE_GRAPHICS1 | DE_GRAPHICS2 | SE_MEMWRITE,  1 },
  38        { DRM_FORMAT_ARGB8888, DE_VIDEO1 | DE_GRAPHICS1 | DE_GRAPHICS2,  2 },
  39        { DRM_FORMAT_ABGR8888, DE_VIDEO1 | DE_GRAPHICS1 | DE_GRAPHICS2,  3 },
  40        { DRM_FORMAT_XRGB8888, DE_VIDEO1 | DE_GRAPHICS1 | DE_GRAPHICS2 | SE_MEMWRITE,  4 },
  41        { DRM_FORMAT_XBGR8888, DE_VIDEO1 | DE_GRAPHICS1 | DE_GRAPHICS2 | SE_MEMWRITE,  5 },
  42        { DRM_FORMAT_RGB888, DE_VIDEO1 | DE_GRAPHICS1 | DE_GRAPHICS2,  6 },
  43        { DRM_FORMAT_BGR888, DE_VIDEO1 | DE_GRAPHICS1 | DE_GRAPHICS2,  7 },
  44        { DRM_FORMAT_RGBA5551, DE_VIDEO1 | DE_GRAPHICS1 | DE_GRAPHICS2,  8 },
  45        { DRM_FORMAT_ABGR1555, DE_VIDEO1 | DE_GRAPHICS1 | DE_GRAPHICS2,  9 },
  46        { DRM_FORMAT_RGB565, DE_VIDEO1 | DE_GRAPHICS1 | DE_GRAPHICS2, 10 },
  47        { DRM_FORMAT_BGR565, DE_VIDEO1 | DE_GRAPHICS1 | DE_GRAPHICS2, 11 },
  48        { DRM_FORMAT_UYVY, DE_VIDEO1, 12 },
  49        { DRM_FORMAT_YUYV, DE_VIDEO1, 13 },
  50        { DRM_FORMAT_NV12, DE_VIDEO1 | SE_MEMWRITE, 14 },
  51        { DRM_FORMAT_YUV420, DE_VIDEO1, 15 },
  52};
  53
  54#define MALIDP_ID(__group, __format) \
  55        ((((__group) & 0x7) << 3) | ((__format) & 0x7))
  56
  57#define MALIDP_COMMON_FORMATS \
  58        /*    fourcc,   layers supporting the format,      internal id   */ \
  59        { DRM_FORMAT_ARGB2101010, DE_VIDEO1 | DE_GRAPHICS1 | DE_VIDEO2 | SE_MEMWRITE, MALIDP_ID(0, 0) }, \
  60        { DRM_FORMAT_ABGR2101010, DE_VIDEO1 | DE_GRAPHICS1 | DE_VIDEO2 | SE_MEMWRITE, MALIDP_ID(0, 1) }, \
  61        { DRM_FORMAT_RGBA1010102, DE_VIDEO1 | DE_GRAPHICS1 | DE_VIDEO2 | SE_MEMWRITE, MALIDP_ID(0, 2) }, \
  62        { DRM_FORMAT_BGRA1010102, DE_VIDEO1 | DE_GRAPHICS1 | DE_VIDEO2 | SE_MEMWRITE, MALIDP_ID(0, 3) }, \
  63        { DRM_FORMAT_ARGB8888, DE_VIDEO1 | DE_GRAPHICS1 | DE_VIDEO2 | DE_SMART, MALIDP_ID(1, 0) }, \
  64        { DRM_FORMAT_ABGR8888, DE_VIDEO1 | DE_GRAPHICS1 | DE_VIDEO2 | DE_SMART, MALIDP_ID(1, 1) }, \
  65        { DRM_FORMAT_RGBA8888, DE_VIDEO1 | DE_GRAPHICS1 | DE_VIDEO2 | DE_SMART, MALIDP_ID(1, 2) }, \
  66        { DRM_FORMAT_BGRA8888, DE_VIDEO1 | DE_GRAPHICS1 | DE_VIDEO2 | DE_SMART, MALIDP_ID(1, 3) }, \
  67        { DRM_FORMAT_XRGB8888, DE_VIDEO1 | DE_GRAPHICS1 | DE_VIDEO2 | DE_SMART | SE_MEMWRITE, MALIDP_ID(2, 0) }, \
  68        { DRM_FORMAT_XBGR8888, DE_VIDEO1 | DE_GRAPHICS1 | DE_VIDEO2 | DE_SMART | SE_MEMWRITE, MALIDP_ID(2, 1) }, \
  69        { DRM_FORMAT_RGBX8888, DE_VIDEO1 | DE_GRAPHICS1 | DE_VIDEO2 | DE_SMART | SE_MEMWRITE, MALIDP_ID(2, 2) }, \
  70        { DRM_FORMAT_BGRX8888, DE_VIDEO1 | DE_GRAPHICS1 | DE_VIDEO2 | DE_SMART | SE_MEMWRITE, MALIDP_ID(2, 3) }, \
  71        { DRM_FORMAT_RGB888, DE_VIDEO1 | DE_GRAPHICS1 | DE_VIDEO2 | SE_MEMWRITE, MALIDP_ID(3, 0) }, \
  72        { DRM_FORMAT_BGR888, DE_VIDEO1 | DE_GRAPHICS1 | DE_VIDEO2 | SE_MEMWRITE, MALIDP_ID(3, 1) }, \
  73        { DRM_FORMAT_RGBA5551, DE_VIDEO1 | DE_GRAPHICS1 | DE_VIDEO2, MALIDP_ID(4, 0) }, \
  74        { DRM_FORMAT_ABGR1555, DE_VIDEO1 | DE_GRAPHICS1 | DE_VIDEO2, MALIDP_ID(4, 1) }, \
  75        { DRM_FORMAT_RGB565, DE_VIDEO1 | DE_GRAPHICS1 | DE_VIDEO2, MALIDP_ID(4, 2) }, \
  76        { DRM_FORMAT_BGR565, DE_VIDEO1 | DE_GRAPHICS1 | DE_VIDEO2, MALIDP_ID(4, 3) }, \
  77        { DRM_FORMAT_YUYV, DE_VIDEO1 | DE_VIDEO2, MALIDP_ID(5, 2) },    \
  78        { DRM_FORMAT_UYVY, DE_VIDEO1 | DE_VIDEO2, MALIDP_ID(5, 3) },    \
  79        { DRM_FORMAT_NV12, DE_VIDEO1 | DE_VIDEO2 | SE_MEMWRITE, MALIDP_ID(5, 6) },      \
  80        { DRM_FORMAT_YUV420, DE_VIDEO1 | DE_VIDEO2, MALIDP_ID(5, 7) }, \
  81        { DRM_FORMAT_X0L2, DE_VIDEO1 | DE_VIDEO2, MALIDP_ID(6, 6)}
  82
  83static const struct malidp_format_id malidp550_de_formats[] = {
  84        MALIDP_COMMON_FORMATS,
  85};
  86
  87static const struct malidp_format_id malidp650_de_formats[] = {
  88        MALIDP_COMMON_FORMATS,
  89        { DRM_FORMAT_X0L0, DE_VIDEO1 | DE_VIDEO2, MALIDP_ID(5, 4)},
  90};
  91
  92static const struct malidp_layer malidp500_layers[] = {
  93        /* id, base address, fb pointer address base, stride offset,
  94         *      yuv2rgb matrix offset, mmu control register offset, rotation_features
  95         */
  96        { DE_VIDEO1, MALIDP500_DE_LV_BASE, MALIDP500_DE_LV_PTR_BASE,
  97                MALIDP_DE_LV_STRIDE0, MALIDP500_LV_YUV2RGB, 0, ROTATE_ANY },
  98        { DE_GRAPHICS1, MALIDP500_DE_LG1_BASE, MALIDP500_DE_LG1_PTR_BASE,
  99                MALIDP_DE_LG_STRIDE, 0, 0, ROTATE_ANY },
 100        { DE_GRAPHICS2, MALIDP500_DE_LG2_BASE, MALIDP500_DE_LG2_PTR_BASE,
 101                MALIDP_DE_LG_STRIDE, 0, 0, ROTATE_ANY },
 102};
 103
 104static const struct malidp_layer malidp550_layers[] = {
 105        /* id, base address, fb pointer address base, stride offset,
 106         *      yuv2rgb matrix offset, mmu control register offset, rotation_features
 107         */
 108        { DE_VIDEO1, MALIDP550_DE_LV1_BASE, MALIDP550_DE_LV1_PTR_BASE,
 109                MALIDP_DE_LV_STRIDE0, MALIDP550_LV_YUV2RGB, 0, ROTATE_ANY },
 110        { DE_GRAPHICS1, MALIDP550_DE_LG_BASE, MALIDP550_DE_LG_PTR_BASE,
 111                MALIDP_DE_LG_STRIDE, 0, 0, ROTATE_ANY },
 112        { DE_VIDEO2, MALIDP550_DE_LV2_BASE, MALIDP550_DE_LV2_PTR_BASE,
 113                MALIDP_DE_LV_STRIDE0, MALIDP550_LV_YUV2RGB, 0, ROTATE_ANY },
 114        { DE_SMART, MALIDP550_DE_LS_BASE, MALIDP550_DE_LS_PTR_BASE,
 115                MALIDP550_DE_LS_R1_STRIDE, 0, 0, ROTATE_NONE },
 116};
 117
 118static const struct malidp_layer malidp650_layers[] = {
 119        /* id, base address, fb pointer address base, stride offset,
 120         *      yuv2rgb matrix offset, mmu control register offset,
 121         *      rotation_features
 122         */
 123        { DE_VIDEO1, MALIDP550_DE_LV1_BASE, MALIDP550_DE_LV1_PTR_BASE,
 124                MALIDP_DE_LV_STRIDE0, MALIDP550_LV_YUV2RGB,
 125                MALIDP650_DE_LV_MMU_CTRL, ROTATE_ANY },
 126        { DE_GRAPHICS1, MALIDP550_DE_LG_BASE, MALIDP550_DE_LG_PTR_BASE,
 127                MALIDP_DE_LG_STRIDE, 0, MALIDP650_DE_LG_MMU_CTRL,
 128                ROTATE_COMPRESSED },
 129        { DE_VIDEO2, MALIDP550_DE_LV2_BASE, MALIDP550_DE_LV2_PTR_BASE,
 130                MALIDP_DE_LV_STRIDE0, MALIDP550_LV_YUV2RGB,
 131                MALIDP650_DE_LV_MMU_CTRL, ROTATE_ANY },
 132        { DE_SMART, MALIDP550_DE_LS_BASE, MALIDP550_DE_LS_PTR_BASE,
 133                MALIDP550_DE_LS_R1_STRIDE, 0, MALIDP650_DE_LS_MMU_CTRL,
 134                ROTATE_NONE },
 135};
 136
 137#define SE_N_SCALING_COEFFS     96
 138static const u16 dp500_se_scaling_coeffs[][SE_N_SCALING_COEFFS] = {
 139        [MALIDP_UPSCALING_COEFFS - 1] = {
 140                0x0000, 0x0001, 0x0007, 0x0011, 0x001e, 0x002e, 0x003f, 0x0052,
 141                0x0064, 0x0073, 0x007d, 0x0080, 0x007a, 0x006c, 0x0053, 0x002f,
 142                0x0000, 0x3fc6, 0x3f83, 0x3f39, 0x3eea, 0x3e9b, 0x3e4f, 0x3e0a,
 143                0x3dd4, 0x3db0, 0x3da2, 0x3db1, 0x3dde, 0x3e2f, 0x3ea5, 0x3f40,
 144                0x0000, 0x00e5, 0x01ee, 0x0315, 0x0456, 0x05aa, 0x0709, 0x086c,
 145                0x09c9, 0x0b15, 0x0c4a, 0x0d5d, 0x0e4a, 0x0f06, 0x0f91, 0x0fe5,
 146                0x1000, 0x0fe5, 0x0f91, 0x0f06, 0x0e4a, 0x0d5d, 0x0c4a, 0x0b15,
 147                0x09c9, 0x086c, 0x0709, 0x05aa, 0x0456, 0x0315, 0x01ee, 0x00e5,
 148                0x0000, 0x3f40, 0x3ea5, 0x3e2f, 0x3dde, 0x3db1, 0x3da2, 0x3db0,
 149                0x3dd4, 0x3e0a, 0x3e4f, 0x3e9b, 0x3eea, 0x3f39, 0x3f83, 0x3fc6,
 150                0x0000, 0x002f, 0x0053, 0x006c, 0x007a, 0x0080, 0x007d, 0x0073,
 151                0x0064, 0x0052, 0x003f, 0x002e, 0x001e, 0x0011, 0x0007, 0x0001
 152        },
 153        [MALIDP_DOWNSCALING_1_5_COEFFS - 1] = {
 154                0x0059, 0x004f, 0x0041, 0x002e, 0x0016, 0x3ffb, 0x3fd9, 0x3fb4,
 155                0x3f8c, 0x3f62, 0x3f36, 0x3f09, 0x3edd, 0x3eb3, 0x3e8d, 0x3e6c,
 156                0x3e52, 0x3e3f, 0x3e35, 0x3e37, 0x3e46, 0x3e61, 0x3e8c, 0x3ec5,
 157                0x3f0f, 0x3f68, 0x3fd1, 0x004a, 0x00d3, 0x0169, 0x020b, 0x02b8,
 158                0x036e, 0x042d, 0x04f2, 0x05b9, 0x0681, 0x0745, 0x0803, 0x08ba,
 159                0x0965, 0x0a03, 0x0a91, 0x0b0d, 0x0b75, 0x0bc6, 0x0c00, 0x0c20,
 160                0x0c28, 0x0c20, 0x0c00, 0x0bc6, 0x0b75, 0x0b0d, 0x0a91, 0x0a03,
 161                0x0965, 0x08ba, 0x0803, 0x0745, 0x0681, 0x05b9, 0x04f2, 0x042d,
 162                0x036e, 0x02b8, 0x020b, 0x0169, 0x00d3, 0x004a, 0x3fd1, 0x3f68,
 163                0x3f0f, 0x3ec5, 0x3e8c, 0x3e61, 0x3e46, 0x3e37, 0x3e35, 0x3e3f,
 164                0x3e52, 0x3e6c, 0x3e8d, 0x3eb3, 0x3edd, 0x3f09, 0x3f36, 0x3f62,
 165                0x3f8c, 0x3fb4, 0x3fd9, 0x3ffb, 0x0016, 0x002e, 0x0041, 0x004f
 166        },
 167        [MALIDP_DOWNSCALING_2_COEFFS - 1] = {
 168                0x3f19, 0x3f03, 0x3ef0, 0x3edf, 0x3ed0, 0x3ec5, 0x3ebd, 0x3eb9,
 169                0x3eb9, 0x3ebf, 0x3eca, 0x3ed9, 0x3eef, 0x3f0a, 0x3f2c, 0x3f52,
 170                0x3f7f, 0x3fb0, 0x3fe8, 0x0026, 0x006a, 0x00b4, 0x0103, 0x0158,
 171                0x01b1, 0x020d, 0x026c, 0x02cd, 0x032f, 0x0392, 0x03f4, 0x0455,
 172                0x04b4, 0x051e, 0x0585, 0x05eb, 0x064c, 0x06a8, 0x06fe, 0x074e,
 173                0x0796, 0x07d5, 0x080c, 0x0839, 0x085c, 0x0875, 0x0882, 0x0887,
 174                0x0881, 0x0887, 0x0882, 0x0875, 0x085c, 0x0839, 0x080c, 0x07d5,
 175                0x0796, 0x074e, 0x06fe, 0x06a8, 0x064c, 0x05eb, 0x0585, 0x051e,
 176                0x04b4, 0x0455, 0x03f4, 0x0392, 0x032f, 0x02cd, 0x026c, 0x020d,
 177                0x01b1, 0x0158, 0x0103, 0x00b4, 0x006a, 0x0026, 0x3fe8, 0x3fb0,
 178                0x3f7f, 0x3f52, 0x3f2c, 0x3f0a, 0x3eef, 0x3ed9, 0x3eca, 0x3ebf,
 179                0x3eb9, 0x3eb9, 0x3ebd, 0x3ec5, 0x3ed0, 0x3edf, 0x3ef0, 0x3f03
 180        },
 181        [MALIDP_DOWNSCALING_2_75_COEFFS - 1] = {
 182                0x3f51, 0x3f60, 0x3f71, 0x3f84, 0x3f98, 0x3faf, 0x3fc8, 0x3fe3,
 183                0x0000, 0x001f, 0x0040, 0x0064, 0x008a, 0x00b1, 0x00da, 0x0106,
 184                0x0133, 0x0160, 0x018e, 0x01bd, 0x01ec, 0x021d, 0x024e, 0x0280,
 185                0x02b2, 0x02e4, 0x0317, 0x0349, 0x037c, 0x03ad, 0x03df, 0x0410,
 186                0x0440, 0x0468, 0x048f, 0x04b3, 0x04d6, 0x04f8, 0x0516, 0x0533,
 187                0x054e, 0x0566, 0x057c, 0x0590, 0x05a0, 0x05ae, 0x05ba, 0x05c3,
 188                0x05c9, 0x05c3, 0x05ba, 0x05ae, 0x05a0, 0x0590, 0x057c, 0x0566,
 189                0x054e, 0x0533, 0x0516, 0x04f8, 0x04d6, 0x04b3, 0x048f, 0x0468,
 190                0x0440, 0x0410, 0x03df, 0x03ad, 0x037c, 0x0349, 0x0317, 0x02e4,
 191                0x02b2, 0x0280, 0x024e, 0x021d, 0x01ec, 0x01bd, 0x018e, 0x0160,
 192                0x0133, 0x0106, 0x00da, 0x00b1, 0x008a, 0x0064, 0x0040, 0x001f,
 193                0x0000, 0x3fe3, 0x3fc8, 0x3faf, 0x3f98, 0x3f84, 0x3f71, 0x3f60
 194        },
 195        [MALIDP_DOWNSCALING_4_COEFFS - 1] = {
 196                0x0094, 0x00a9, 0x00be, 0x00d4, 0x00ea, 0x0101, 0x0118, 0x012f,
 197                0x0148, 0x0160, 0x017a, 0x0193, 0x01ae, 0x01c8, 0x01e4, 0x01ff,
 198                0x021c, 0x0233, 0x024a, 0x0261, 0x0278, 0x028f, 0x02a6, 0x02bd,
 199                0x02d4, 0x02eb, 0x0302, 0x0319, 0x032f, 0x0346, 0x035d, 0x0374,
 200                0x038a, 0x0397, 0x03a3, 0x03af, 0x03bb, 0x03c6, 0x03d1, 0x03db,
 201                0x03e4, 0x03ed, 0x03f6, 0x03fe, 0x0406, 0x040d, 0x0414, 0x041a,
 202                0x0420, 0x041a, 0x0414, 0x040d, 0x0406, 0x03fe, 0x03f6, 0x03ed,
 203                0x03e4, 0x03db, 0x03d1, 0x03c6, 0x03bb, 0x03af, 0x03a3, 0x0397,
 204                0x038a, 0x0374, 0x035d, 0x0346, 0x032f, 0x0319, 0x0302, 0x02eb,
 205                0x02d4, 0x02bd, 0x02a6, 0x028f, 0x0278, 0x0261, 0x024a, 0x0233,
 206                0x021c, 0x01ff, 0x01e4, 0x01c8, 0x01ae, 0x0193, 0x017a, 0x0160,
 207                0x0148, 0x012f, 0x0118, 0x0101, 0x00ea, 0x00d4, 0x00be, 0x00a9
 208        },
 209};
 210
 211#define MALIDP_DE_DEFAULT_PREFETCH_START        5
 212
 213static int malidp500_query_hw(struct malidp_hw_device *hwdev)
 214{
 215        u32 conf = malidp_hw_read(hwdev, MALIDP500_CONFIG_ID);
 216        /* bit 4 of the CONFIG_ID register holds the line size multiplier */
 217        u8 ln_size_mult = conf & 0x10 ? 2 : 1;
 218
 219        hwdev->min_line_size = 2;
 220        hwdev->max_line_size = SZ_2K * ln_size_mult;
 221        hwdev->rotation_memory[0] = SZ_1K * 64 * ln_size_mult;
 222        hwdev->rotation_memory[1] = 0; /* no second rotation memory bank */
 223
 224        return 0;
 225}
 226
 227static void malidp500_enter_config_mode(struct malidp_hw_device *hwdev)
 228{
 229        u32 status, count = 100;
 230
 231        malidp_hw_setbits(hwdev, MALIDP500_DC_CONFIG_REQ, MALIDP500_DC_CONTROL);
 232        while (count) {
 233                status = malidp_hw_read(hwdev, hwdev->hw->map.dc_base + MALIDP_REG_STATUS);
 234                if ((status & MALIDP500_DC_CONFIG_REQ) == MALIDP500_DC_CONFIG_REQ)
 235                        break;
 236                /*
 237                 * entering config mode can take as long as the rendering
 238                 * of a full frame, hence the long sleep here
 239                 */
 240                usleep_range(1000, 10000);
 241                count--;
 242        }
 243        WARN(count == 0, "timeout while entering config mode");
 244}
 245
 246static void malidp500_leave_config_mode(struct malidp_hw_device *hwdev)
 247{
 248        u32 status, count = 100;
 249
 250        malidp_hw_clearbits(hwdev, MALIDP_CFG_VALID, MALIDP500_CONFIG_VALID);
 251        malidp_hw_clearbits(hwdev, MALIDP500_DC_CONFIG_REQ, MALIDP500_DC_CONTROL);
 252        while (count) {
 253                status = malidp_hw_read(hwdev, hwdev->hw->map.dc_base + MALIDP_REG_STATUS);
 254                if ((status & MALIDP500_DC_CONFIG_REQ) == 0)
 255                        break;
 256                usleep_range(100, 1000);
 257                count--;
 258        }
 259        WARN(count == 0, "timeout while leaving config mode");
 260}
 261
 262static bool malidp500_in_config_mode(struct malidp_hw_device *hwdev)
 263{
 264        u32 status;
 265
 266        status = malidp_hw_read(hwdev, hwdev->hw->map.dc_base + MALIDP_REG_STATUS);
 267        if ((status & MALIDP500_DC_CONFIG_REQ) == MALIDP500_DC_CONFIG_REQ)
 268                return true;
 269
 270        return false;
 271}
 272
 273static void malidp500_set_config_valid(struct malidp_hw_device *hwdev, u8 value)
 274{
 275        if (value)
 276                malidp_hw_setbits(hwdev, MALIDP_CFG_VALID, MALIDP500_CONFIG_VALID);
 277        else
 278                malidp_hw_clearbits(hwdev, MALIDP_CFG_VALID, MALIDP500_CONFIG_VALID);
 279}
 280
 281static void malidp500_modeset(struct malidp_hw_device *hwdev, struct videomode *mode)
 282{
 283        u32 val = 0;
 284
 285        malidp_hw_write(hwdev, hwdev->output_color_depth,
 286                hwdev->hw->map.out_depth_base);
 287        malidp_hw_clearbits(hwdev, MALIDP500_DC_CLEAR_MASK, MALIDP500_DC_CONTROL);
 288        if (mode->flags & DISPLAY_FLAGS_HSYNC_HIGH)
 289                val |= MALIDP500_HSYNCPOL;
 290        if (mode->flags & DISPLAY_FLAGS_VSYNC_HIGH)
 291                val |= MALIDP500_VSYNCPOL;
 292        val |= MALIDP_DE_DEFAULT_PREFETCH_START;
 293        malidp_hw_setbits(hwdev, val, MALIDP500_DC_CONTROL);
 294
 295        /*
 296         * Mali-DP500 encodes the background color like this:
 297         *    - red   @ MALIDP500_BGND_COLOR[12:0]
 298         *    - green @ MALIDP500_BGND_COLOR[27:16]
 299         *    - blue  @ (MALIDP500_BGND_COLOR + 4)[12:0]
 300         */
 301        val = ((MALIDP_BGND_COLOR_G & 0xfff) << 16) |
 302              (MALIDP_BGND_COLOR_R & 0xfff);
 303        malidp_hw_write(hwdev, val, MALIDP500_BGND_COLOR);
 304        malidp_hw_write(hwdev, MALIDP_BGND_COLOR_B, MALIDP500_BGND_COLOR + 4);
 305
 306        val = MALIDP_DE_H_FRONTPORCH(mode->hfront_porch) |
 307                MALIDP_DE_H_BACKPORCH(mode->hback_porch);
 308        malidp_hw_write(hwdev, val, MALIDP500_TIMINGS_BASE + MALIDP_DE_H_TIMINGS);
 309
 310        val = MALIDP500_DE_V_FRONTPORCH(mode->vfront_porch) |
 311                MALIDP_DE_V_BACKPORCH(mode->vback_porch);
 312        malidp_hw_write(hwdev, val, MALIDP500_TIMINGS_BASE + MALIDP_DE_V_TIMINGS);
 313
 314        val = MALIDP_DE_H_SYNCWIDTH(mode->hsync_len) |
 315                MALIDP_DE_V_SYNCWIDTH(mode->vsync_len);
 316        malidp_hw_write(hwdev, val, MALIDP500_TIMINGS_BASE + MALIDP_DE_SYNC_WIDTH);
 317
 318        val = MALIDP_DE_H_ACTIVE(mode->hactive) | MALIDP_DE_V_ACTIVE(mode->vactive);
 319        malidp_hw_write(hwdev, val, MALIDP500_TIMINGS_BASE + MALIDP_DE_HV_ACTIVE);
 320
 321        if (mode->flags & DISPLAY_FLAGS_INTERLACED)
 322                malidp_hw_setbits(hwdev, MALIDP_DISP_FUNC_ILACED, MALIDP_DE_DISPLAY_FUNC);
 323        else
 324                malidp_hw_clearbits(hwdev, MALIDP_DISP_FUNC_ILACED, MALIDP_DE_DISPLAY_FUNC);
 325}
 326
 327static int malidp500_rotmem_required(struct malidp_hw_device *hwdev, u16 w, u16 h, u32 fmt)
 328{
 329        /*
 330         * Each layer needs enough rotation memory to fit 8 lines
 331         * worth of pixel data. Required size is then:
 332         *    size = rotated_width * (bpp / 8) * 8;
 333         */
 334        return w * drm_format_plane_cpp(fmt, 0) * 8;
 335}
 336
 337static void malidp500_se_write_pp_coefftab(struct malidp_hw_device *hwdev,
 338                                           u32 direction,
 339                                           u16 addr,
 340                                           u8 coeffs_id)
 341{
 342        int i;
 343        u16 scaling_control = MALIDP500_SE_CONTROL + MALIDP_SE_SCALING_CONTROL;
 344
 345        malidp_hw_write(hwdev,
 346                        direction | (addr & MALIDP_SE_COEFFTAB_ADDR_MASK),
 347                        scaling_control + MALIDP_SE_COEFFTAB_ADDR);
 348        for (i = 0; i < ARRAY_SIZE(dp500_se_scaling_coeffs); ++i)
 349                malidp_hw_write(hwdev, MALIDP_SE_SET_COEFFTAB_DATA(
 350                                dp500_se_scaling_coeffs[coeffs_id][i]),
 351                                scaling_control + MALIDP_SE_COEFFTAB_DATA);
 352}
 353
 354static int malidp500_se_set_scaling_coeffs(struct malidp_hw_device *hwdev,
 355                                           struct malidp_se_config *se_config,
 356                                           struct malidp_se_config *old_config)
 357{
 358        /* Get array indices into dp500_se_scaling_coeffs. */
 359        u8 h = (u8)se_config->hcoeff - 1;
 360        u8 v = (u8)se_config->vcoeff - 1;
 361
 362        if (WARN_ON(h >= ARRAY_SIZE(dp500_se_scaling_coeffs) ||
 363                    v >= ARRAY_SIZE(dp500_se_scaling_coeffs)))
 364                return -EINVAL;
 365
 366        if ((h == v) && (se_config->hcoeff != old_config->hcoeff ||
 367                         se_config->vcoeff != old_config->vcoeff)) {
 368                malidp500_se_write_pp_coefftab(hwdev,
 369                                               (MALIDP_SE_V_COEFFTAB |
 370                                                MALIDP_SE_H_COEFFTAB),
 371                                               0, v);
 372        } else {
 373                if (se_config->vcoeff != old_config->vcoeff)
 374                        malidp500_se_write_pp_coefftab(hwdev,
 375                                                       MALIDP_SE_V_COEFFTAB,
 376                                                       0, v);
 377                if (se_config->hcoeff != old_config->hcoeff)
 378                        malidp500_se_write_pp_coefftab(hwdev,
 379                                                       MALIDP_SE_H_COEFFTAB,
 380                                                       0, h);
 381        }
 382
 383        return 0;
 384}
 385
 386static long malidp500_se_calc_mclk(struct malidp_hw_device *hwdev,
 387                                   struct malidp_se_config *se_config,
 388                                   struct videomode *vm)
 389{
 390        unsigned long mclk;
 391        unsigned long pxlclk = vm->pixelclock; /* Hz */
 392        unsigned long htotal = vm->hactive + vm->hfront_porch +
 393                               vm->hback_porch + vm->hsync_len;
 394        unsigned long input_size = se_config->input_w * se_config->input_h;
 395        unsigned long a = 10;
 396        long ret;
 397
 398        /*
 399         * mclk = max(a, 1.5) * pxlclk
 400         *
 401         * To avoid float calculaiton, using 15 instead of 1.5 and div by
 402         * 10 to get mclk.
 403         */
 404        if (se_config->scale_enable) {
 405                a = 15 * input_size / (htotal * se_config->output_h);
 406                if (a < 15)
 407                        a = 15;
 408        }
 409        mclk = a * pxlclk / 10;
 410        ret = clk_get_rate(hwdev->mclk);
 411        if (ret < mclk) {
 412                DRM_DEBUG_DRIVER("mclk requirement of %lu kHz can't be met.\n",
 413                                 mclk / 1000);
 414                return -EINVAL;
 415        }
 416        return ret;
 417}
 418
 419static int malidp500_enable_memwrite(struct malidp_hw_device *hwdev,
 420                                     dma_addr_t *addrs, s32 *pitches,
 421                                     int num_planes, u16 w, u16 h, u32 fmt_id,
 422                                     const s16 *rgb2yuv_coeffs)
 423{
 424        u32 base = MALIDP500_SE_MEMWRITE_BASE;
 425        u32 de_base = malidp_get_block_base(hwdev, MALIDP_DE_BLOCK);
 426
 427        /* enable the scaling engine block */
 428        malidp_hw_setbits(hwdev, MALIDP_SCALE_ENGINE_EN, de_base + MALIDP_DE_DISPLAY_FUNC);
 429
 430        /* restart the writeback if already enabled */
 431        if (hwdev->mw_state != MW_NOT_ENABLED)
 432                hwdev->mw_state = MW_RESTART;
 433        else
 434                hwdev->mw_state = MW_START;
 435
 436        malidp_hw_write(hwdev, fmt_id, base + MALIDP_MW_FORMAT);
 437        switch (num_planes) {
 438        case 2:
 439                malidp_hw_write(hwdev, lower_32_bits(addrs[1]), base + MALIDP_MW_P2_PTR_LOW);
 440                malidp_hw_write(hwdev, upper_32_bits(addrs[1]), base + MALIDP_MW_P2_PTR_HIGH);
 441                malidp_hw_write(hwdev, pitches[1], base + MALIDP_MW_P2_STRIDE);
 442                /* fall through */
 443        case 1:
 444                malidp_hw_write(hwdev, lower_32_bits(addrs[0]), base + MALIDP_MW_P1_PTR_LOW);
 445                malidp_hw_write(hwdev, upper_32_bits(addrs[0]), base + MALIDP_MW_P1_PTR_HIGH);
 446                malidp_hw_write(hwdev, pitches[0], base + MALIDP_MW_P1_STRIDE);
 447                break;
 448        default:
 449                WARN(1, "Invalid number of planes");
 450        }
 451
 452        malidp_hw_write(hwdev, MALIDP_DE_H_ACTIVE(w) | MALIDP_DE_V_ACTIVE(h),
 453                        MALIDP500_SE_MEMWRITE_OUT_SIZE);
 454
 455        if (rgb2yuv_coeffs) {
 456                int i;
 457
 458                for (i = 0; i < MALIDP_COLORADJ_NUM_COEFFS; i++) {
 459                        malidp_hw_write(hwdev, rgb2yuv_coeffs[i],
 460                                        MALIDP500_SE_RGB_YUV_COEFFS + i * 4);
 461                }
 462        }
 463
 464        malidp_hw_setbits(hwdev, MALIDP_SE_MEMWRITE_EN, MALIDP500_SE_CONTROL);
 465
 466        return 0;
 467}
 468
 469static void malidp500_disable_memwrite(struct malidp_hw_device *hwdev)
 470{
 471        u32 base = malidp_get_block_base(hwdev, MALIDP_DE_BLOCK);
 472
 473        if (hwdev->mw_state == MW_START || hwdev->mw_state == MW_RESTART)
 474                hwdev->mw_state = MW_STOP;
 475        malidp_hw_clearbits(hwdev, MALIDP_SE_MEMWRITE_EN, MALIDP500_SE_CONTROL);
 476        malidp_hw_clearbits(hwdev, MALIDP_SCALE_ENGINE_EN, base + MALIDP_DE_DISPLAY_FUNC);
 477}
 478
 479static int malidp550_query_hw(struct malidp_hw_device *hwdev)
 480{
 481        u32 conf = malidp_hw_read(hwdev, MALIDP550_CONFIG_ID);
 482        u8 ln_size = (conf >> 4) & 0x3, rsize;
 483
 484        hwdev->min_line_size = 2;
 485
 486        switch (ln_size) {
 487        case 0:
 488                hwdev->max_line_size = SZ_2K;
 489                /* two banks of 64KB for rotation memory */
 490                rsize = 64;
 491                break;
 492        case 1:
 493                hwdev->max_line_size = SZ_4K;
 494                /* two banks of 128KB for rotation memory */
 495                rsize = 128;
 496                break;
 497        case 2:
 498                hwdev->max_line_size = 1280;
 499                /* two banks of 40KB for rotation memory */
 500                rsize = 40;
 501                break;
 502        case 3:
 503                /* reserved value */
 504                hwdev->max_line_size = 0;
 505                return -EINVAL;
 506        }
 507
 508        hwdev->rotation_memory[0] = hwdev->rotation_memory[1] = rsize * SZ_1K;
 509        return 0;
 510}
 511
 512static void malidp550_enter_config_mode(struct malidp_hw_device *hwdev)
 513{
 514        u32 status, count = 100;
 515
 516        malidp_hw_setbits(hwdev, MALIDP550_DC_CONFIG_REQ, MALIDP550_DC_CONTROL);
 517        while (count) {
 518                status = malidp_hw_read(hwdev, hwdev->hw->map.dc_base + MALIDP_REG_STATUS);
 519                if ((status & MALIDP550_DC_CONFIG_REQ) == MALIDP550_DC_CONFIG_REQ)
 520                        break;
 521                /*
 522                 * entering config mode can take as long as the rendering
 523                 * of a full frame, hence the long sleep here
 524                 */
 525                usleep_range(1000, 10000);
 526                count--;
 527        }
 528        WARN(count == 0, "timeout while entering config mode");
 529}
 530
 531static void malidp550_leave_config_mode(struct malidp_hw_device *hwdev)
 532{
 533        u32 status, count = 100;
 534
 535        malidp_hw_clearbits(hwdev, MALIDP_CFG_VALID, MALIDP550_CONFIG_VALID);
 536        malidp_hw_clearbits(hwdev, MALIDP550_DC_CONFIG_REQ, MALIDP550_DC_CONTROL);
 537        while (count) {
 538                status = malidp_hw_read(hwdev, hwdev->hw->map.dc_base + MALIDP_REG_STATUS);
 539                if ((status & MALIDP550_DC_CONFIG_REQ) == 0)
 540                        break;
 541                usleep_range(100, 1000);
 542                count--;
 543        }
 544        WARN(count == 0, "timeout while leaving config mode");
 545}
 546
 547static bool malidp550_in_config_mode(struct malidp_hw_device *hwdev)
 548{
 549        u32 status;
 550
 551        status = malidp_hw_read(hwdev, hwdev->hw->map.dc_base + MALIDP_REG_STATUS);
 552        if ((status & MALIDP550_DC_CONFIG_REQ) == MALIDP550_DC_CONFIG_REQ)
 553                return true;
 554
 555        return false;
 556}
 557
 558static void malidp550_set_config_valid(struct malidp_hw_device *hwdev, u8 value)
 559{
 560        if (value)
 561                malidp_hw_setbits(hwdev, MALIDP_CFG_VALID, MALIDP550_CONFIG_VALID);
 562        else
 563                malidp_hw_clearbits(hwdev, MALIDP_CFG_VALID, MALIDP550_CONFIG_VALID);
 564}
 565
 566static void malidp550_modeset(struct malidp_hw_device *hwdev, struct videomode *mode)
 567{
 568        u32 val = MALIDP_DE_DEFAULT_PREFETCH_START;
 569
 570        malidp_hw_write(hwdev, hwdev->output_color_depth,
 571                hwdev->hw->map.out_depth_base);
 572        malidp_hw_write(hwdev, val, MALIDP550_DE_CONTROL);
 573        /*
 574         * Mali-DP550 and Mali-DP650 encode the background color like this:
 575         *   - red   @ MALIDP550_DE_BGND_COLOR[23:16]
 576         *   - green @ MALIDP550_DE_BGND_COLOR[15:8]
 577         *   - blue  @ MALIDP550_DE_BGND_COLOR[7:0]
 578         *
 579         * We need to truncate the least significant 4 bits from the default
 580         * MALIDP_BGND_COLOR_x values
 581         */
 582        val = (((MALIDP_BGND_COLOR_R >> 4) & 0xff) << 16) |
 583              (((MALIDP_BGND_COLOR_G >> 4) & 0xff) << 8) |
 584              ((MALIDP_BGND_COLOR_B >> 4) & 0xff);
 585        malidp_hw_write(hwdev, val, MALIDP550_DE_BGND_COLOR);
 586
 587        val = MALIDP_DE_H_FRONTPORCH(mode->hfront_porch) |
 588                MALIDP_DE_H_BACKPORCH(mode->hback_porch);
 589        malidp_hw_write(hwdev, val, MALIDP550_TIMINGS_BASE + MALIDP_DE_H_TIMINGS);
 590
 591        val = MALIDP550_DE_V_FRONTPORCH(mode->vfront_porch) |
 592                MALIDP_DE_V_BACKPORCH(mode->vback_porch);
 593        malidp_hw_write(hwdev, val, MALIDP550_TIMINGS_BASE + MALIDP_DE_V_TIMINGS);
 594
 595        val = MALIDP_DE_H_SYNCWIDTH(mode->hsync_len) |
 596                MALIDP_DE_V_SYNCWIDTH(mode->vsync_len);
 597        if (mode->flags & DISPLAY_FLAGS_HSYNC_HIGH)
 598                val |= MALIDP550_HSYNCPOL;
 599        if (mode->flags & DISPLAY_FLAGS_VSYNC_HIGH)
 600                val |= MALIDP550_VSYNCPOL;
 601        malidp_hw_write(hwdev, val, MALIDP550_TIMINGS_BASE + MALIDP_DE_SYNC_WIDTH);
 602
 603        val = MALIDP_DE_H_ACTIVE(mode->hactive) | MALIDP_DE_V_ACTIVE(mode->vactive);
 604        malidp_hw_write(hwdev, val, MALIDP550_TIMINGS_BASE + MALIDP_DE_HV_ACTIVE);
 605
 606        if (mode->flags & DISPLAY_FLAGS_INTERLACED)
 607                malidp_hw_setbits(hwdev, MALIDP_DISP_FUNC_ILACED, MALIDP_DE_DISPLAY_FUNC);
 608        else
 609                malidp_hw_clearbits(hwdev, MALIDP_DISP_FUNC_ILACED, MALIDP_DE_DISPLAY_FUNC);
 610}
 611
 612static int malidp550_rotmem_required(struct malidp_hw_device *hwdev, u16 w, u16 h, u32 fmt)
 613{
 614        u32 bytes_per_col;
 615
 616        switch (fmt) {
 617        /* 8 lines at 4 bytes per pixel */
 618        case DRM_FORMAT_ARGB2101010:
 619        case DRM_FORMAT_ABGR2101010:
 620        case DRM_FORMAT_RGBA1010102:
 621        case DRM_FORMAT_BGRA1010102:
 622        case DRM_FORMAT_ARGB8888:
 623        case DRM_FORMAT_ABGR8888:
 624        case DRM_FORMAT_RGBA8888:
 625        case DRM_FORMAT_BGRA8888:
 626        case DRM_FORMAT_XRGB8888:
 627        case DRM_FORMAT_XBGR8888:
 628        case DRM_FORMAT_RGBX8888:
 629        case DRM_FORMAT_BGRX8888:
 630        case DRM_FORMAT_RGB888:
 631        case DRM_FORMAT_BGR888:
 632        /* 16 lines at 2 bytes per pixel */
 633        case DRM_FORMAT_RGBA5551:
 634        case DRM_FORMAT_ABGR1555:
 635        case DRM_FORMAT_RGB565:
 636        case DRM_FORMAT_BGR565:
 637        case DRM_FORMAT_UYVY:
 638        case DRM_FORMAT_YUYV:
 639        case DRM_FORMAT_X0L0:
 640        case DRM_FORMAT_X0L2:
 641                bytes_per_col = 32;
 642                break;
 643        /* 16 lines at 1.5 bytes per pixel */
 644        case DRM_FORMAT_NV12:
 645        case DRM_FORMAT_YUV420:
 646                bytes_per_col = 24;
 647                break;
 648        default:
 649                return -EINVAL;
 650        }
 651
 652        return w * bytes_per_col;
 653}
 654
 655static int malidp550_se_set_scaling_coeffs(struct malidp_hw_device *hwdev,
 656                                           struct malidp_se_config *se_config,
 657                                           struct malidp_se_config *old_config)
 658{
 659        u32 mask = MALIDP550_SE_CTL_VCSEL(MALIDP550_SE_CTL_SEL_MASK) |
 660                   MALIDP550_SE_CTL_HCSEL(MALIDP550_SE_CTL_SEL_MASK);
 661        u32 new_value = MALIDP550_SE_CTL_VCSEL(se_config->vcoeff) |
 662                        MALIDP550_SE_CTL_HCSEL(se_config->hcoeff);
 663
 664        malidp_hw_clearbits(hwdev, mask, MALIDP550_SE_CONTROL);
 665        malidp_hw_setbits(hwdev, new_value, MALIDP550_SE_CONTROL);
 666        return 0;
 667}
 668
 669static long malidp550_se_calc_mclk(struct malidp_hw_device *hwdev,
 670                                   struct malidp_se_config *se_config,
 671                                   struct videomode *vm)
 672{
 673        unsigned long mclk;
 674        unsigned long pxlclk = vm->pixelclock;
 675        unsigned long htotal = vm->hactive + vm->hfront_porch +
 676                               vm->hback_porch + vm->hsync_len;
 677        unsigned long numerator = 1, denominator = 1;
 678        long ret;
 679
 680        if (se_config->scale_enable) {
 681                numerator = max(se_config->input_w, se_config->output_w) *
 682                            se_config->input_h;
 683                numerator += se_config->output_w *
 684                             (se_config->output_h -
 685                              min(se_config->input_h, se_config->output_h));
 686                denominator = (htotal - 2) * se_config->output_h;
 687        }
 688
 689        /* mclk can't be slower than pxlclk. */
 690        if (numerator < denominator)
 691                numerator = denominator = 1;
 692        mclk = (pxlclk * numerator) / denominator;
 693        ret = clk_get_rate(hwdev->mclk);
 694        if (ret < mclk) {
 695                DRM_DEBUG_DRIVER("mclk requirement of %lu kHz can't be met.\n",
 696                                 mclk / 1000);
 697                return -EINVAL;
 698        }
 699        return ret;
 700}
 701
 702static int malidp550_enable_memwrite(struct malidp_hw_device *hwdev,
 703                                     dma_addr_t *addrs, s32 *pitches,
 704                                     int num_planes, u16 w, u16 h, u32 fmt_id,
 705                                     const s16 *rgb2yuv_coeffs)
 706{
 707        u32 base = MALIDP550_SE_MEMWRITE_BASE;
 708        u32 de_base = malidp_get_block_base(hwdev, MALIDP_DE_BLOCK);
 709
 710        /* enable the scaling engine block */
 711        malidp_hw_setbits(hwdev, MALIDP_SCALE_ENGINE_EN, de_base + MALIDP_DE_DISPLAY_FUNC);
 712
 713        hwdev->mw_state = MW_ONESHOT;
 714
 715        malidp_hw_write(hwdev, fmt_id, base + MALIDP_MW_FORMAT);
 716        switch (num_planes) {
 717        case 2:
 718                malidp_hw_write(hwdev, lower_32_bits(addrs[1]), base + MALIDP_MW_P2_PTR_LOW);
 719                malidp_hw_write(hwdev, upper_32_bits(addrs[1]), base + MALIDP_MW_P2_PTR_HIGH);
 720                malidp_hw_write(hwdev, pitches[1], base + MALIDP_MW_P2_STRIDE);
 721                /* fall through */
 722        case 1:
 723                malidp_hw_write(hwdev, lower_32_bits(addrs[0]), base + MALIDP_MW_P1_PTR_LOW);
 724                malidp_hw_write(hwdev, upper_32_bits(addrs[0]), base + MALIDP_MW_P1_PTR_HIGH);
 725                malidp_hw_write(hwdev, pitches[0], base + MALIDP_MW_P1_STRIDE);
 726                break;
 727        default:
 728                WARN(1, "Invalid number of planes");
 729        }
 730
 731        malidp_hw_write(hwdev, MALIDP_DE_H_ACTIVE(w) | MALIDP_DE_V_ACTIVE(h),
 732                        MALIDP550_SE_MEMWRITE_OUT_SIZE);
 733        malidp_hw_setbits(hwdev, MALIDP550_SE_MEMWRITE_ONESHOT | MALIDP_SE_MEMWRITE_EN,
 734                          MALIDP550_SE_CONTROL);
 735
 736        if (rgb2yuv_coeffs) {
 737                int i;
 738
 739                for (i = 0; i < MALIDP_COLORADJ_NUM_COEFFS; i++) {
 740                        malidp_hw_write(hwdev, rgb2yuv_coeffs[i],
 741                                        MALIDP550_SE_RGB_YUV_COEFFS + i * 4);
 742                }
 743        }
 744
 745        return 0;
 746}
 747
 748static void malidp550_disable_memwrite(struct malidp_hw_device *hwdev)
 749{
 750        u32 base = malidp_get_block_base(hwdev, MALIDP_DE_BLOCK);
 751
 752        malidp_hw_clearbits(hwdev, MALIDP550_SE_MEMWRITE_ONESHOT | MALIDP_SE_MEMWRITE_EN,
 753                            MALIDP550_SE_CONTROL);
 754        malidp_hw_clearbits(hwdev, MALIDP_SCALE_ENGINE_EN, base + MALIDP_DE_DISPLAY_FUNC);
 755}
 756
 757static int malidp650_query_hw(struct malidp_hw_device *hwdev)
 758{
 759        u32 conf = malidp_hw_read(hwdev, MALIDP550_CONFIG_ID);
 760        u8 ln_size = (conf >> 4) & 0x3, rsize;
 761
 762        hwdev->min_line_size = 4;
 763
 764        switch (ln_size) {
 765        case 0:
 766        case 2:
 767                /* reserved values */
 768                hwdev->max_line_size = 0;
 769                return -EINVAL;
 770        case 1:
 771                hwdev->max_line_size = SZ_4K;
 772                /* two banks of 128KB for rotation memory */
 773                rsize = 128;
 774                break;
 775        case 3:
 776                hwdev->max_line_size = 2560;
 777                /* two banks of 80KB for rotation memory */
 778                rsize = 80;
 779        }
 780
 781        hwdev->rotation_memory[0] = hwdev->rotation_memory[1] = rsize * SZ_1K;
 782        return 0;
 783}
 784
 785const struct malidp_hw malidp_device[MALIDP_MAX_DEVICES] = {
 786        [MALIDP_500] = {
 787                .map = {
 788                        .coeffs_base = MALIDP500_COEFFS_BASE,
 789                        .se_base = MALIDP500_SE_BASE,
 790                        .dc_base = MALIDP500_DC_BASE,
 791                        .out_depth_base = MALIDP500_OUTPUT_DEPTH,
 792                        .features = 0,  /* no CLEARIRQ register */
 793                        .n_layers = ARRAY_SIZE(malidp500_layers),
 794                        .layers = malidp500_layers,
 795                        .de_irq_map = {
 796                                .irq_mask = MALIDP_DE_IRQ_UNDERRUN |
 797                                            MALIDP500_DE_IRQ_AXI_ERR |
 798                                            MALIDP500_DE_IRQ_VSYNC |
 799                                            MALIDP500_DE_IRQ_GLOBAL,
 800                                .vsync_irq = MALIDP500_DE_IRQ_VSYNC,
 801                                .err_mask = MALIDP_DE_IRQ_UNDERRUN |
 802                                            MALIDP500_DE_IRQ_AXI_ERR |
 803                                            MALIDP500_DE_IRQ_SATURATION,
 804                        },
 805                        .se_irq_map = {
 806                                .irq_mask = MALIDP500_SE_IRQ_CONF_MODE |
 807                                            MALIDP500_SE_IRQ_CONF_VALID |
 808                                            MALIDP500_SE_IRQ_GLOBAL,
 809                                .vsync_irq = MALIDP500_SE_IRQ_CONF_VALID,
 810                                .err_mask = MALIDP500_SE_IRQ_INIT_BUSY |
 811                                            MALIDP500_SE_IRQ_AXI_ERROR |
 812                                            MALIDP500_SE_IRQ_OVERRUN,
 813                        },
 814                        .dc_irq_map = {
 815                                .irq_mask = MALIDP500_DE_IRQ_CONF_VALID,
 816                                .vsync_irq = MALIDP500_DE_IRQ_CONF_VALID,
 817                        },
 818                        .pixel_formats = malidp500_de_formats,
 819                        .n_pixel_formats = ARRAY_SIZE(malidp500_de_formats),
 820                        .bus_align_bytes = 8,
 821                },
 822                .query_hw = malidp500_query_hw,
 823                .enter_config_mode = malidp500_enter_config_mode,
 824                .leave_config_mode = malidp500_leave_config_mode,
 825                .in_config_mode = malidp500_in_config_mode,
 826                .set_config_valid = malidp500_set_config_valid,
 827                .modeset = malidp500_modeset,
 828                .rotmem_required = malidp500_rotmem_required,
 829                .se_set_scaling_coeffs = malidp500_se_set_scaling_coeffs,
 830                .se_calc_mclk = malidp500_se_calc_mclk,
 831                .enable_memwrite = malidp500_enable_memwrite,
 832                .disable_memwrite = malidp500_disable_memwrite,
 833                .features = MALIDP_DEVICE_LV_HAS_3_STRIDES,
 834        },
 835        [MALIDP_550] = {
 836                .map = {
 837                        .coeffs_base = MALIDP550_COEFFS_BASE,
 838                        .se_base = MALIDP550_SE_BASE,
 839                        .dc_base = MALIDP550_DC_BASE,
 840                        .out_depth_base = MALIDP550_DE_OUTPUT_DEPTH,
 841                        .features = MALIDP_REGMAP_HAS_CLEARIRQ,
 842                        .n_layers = ARRAY_SIZE(malidp550_layers),
 843                        .layers = malidp550_layers,
 844                        .de_irq_map = {
 845                                .irq_mask = MALIDP_DE_IRQ_UNDERRUN |
 846                                            MALIDP550_DE_IRQ_VSYNC,
 847                                .vsync_irq = MALIDP550_DE_IRQ_VSYNC,
 848                                .err_mask = MALIDP_DE_IRQ_UNDERRUN |
 849                                            MALIDP550_DE_IRQ_SATURATION |
 850                                            MALIDP550_DE_IRQ_AXI_ERR,
 851                        },
 852                        .se_irq_map = {
 853                                .irq_mask = MALIDP550_SE_IRQ_EOW,
 854                                .vsync_irq = MALIDP550_SE_IRQ_EOW,
 855                                .err_mask  = MALIDP550_SE_IRQ_AXI_ERR |
 856                                             MALIDP550_SE_IRQ_OVR |
 857                                             MALIDP550_SE_IRQ_IBSY,
 858                        },
 859                        .dc_irq_map = {
 860                                .irq_mask = MALIDP550_DC_IRQ_CONF_VALID |
 861                                            MALIDP550_DC_IRQ_SE,
 862                                .vsync_irq = MALIDP550_DC_IRQ_CONF_VALID,
 863                        },
 864                        .pixel_formats = malidp550_de_formats,
 865                        .n_pixel_formats = ARRAY_SIZE(malidp550_de_formats),
 866                        .bus_align_bytes = 8,
 867                },
 868                .query_hw = malidp550_query_hw,
 869                .enter_config_mode = malidp550_enter_config_mode,
 870                .leave_config_mode = malidp550_leave_config_mode,
 871                .in_config_mode = malidp550_in_config_mode,
 872                .set_config_valid = malidp550_set_config_valid,
 873                .modeset = malidp550_modeset,
 874                .rotmem_required = malidp550_rotmem_required,
 875                .se_set_scaling_coeffs = malidp550_se_set_scaling_coeffs,
 876                .se_calc_mclk = malidp550_se_calc_mclk,
 877                .enable_memwrite = malidp550_enable_memwrite,
 878                .disable_memwrite = malidp550_disable_memwrite,
 879                .features = 0,
 880        },
 881        [MALIDP_650] = {
 882                .map = {
 883                        .coeffs_base = MALIDP550_COEFFS_BASE,
 884                        .se_base = MALIDP550_SE_BASE,
 885                        .dc_base = MALIDP550_DC_BASE,
 886                        .out_depth_base = MALIDP550_DE_OUTPUT_DEPTH,
 887                        .features = MALIDP_REGMAP_HAS_CLEARIRQ,
 888                        .n_layers = ARRAY_SIZE(malidp650_layers),
 889                        .layers = malidp650_layers,
 890                        .de_irq_map = {
 891                                .irq_mask = MALIDP_DE_IRQ_UNDERRUN |
 892                                            MALIDP650_DE_IRQ_DRIFT |
 893                                            MALIDP550_DE_IRQ_VSYNC,
 894                                .vsync_irq = MALIDP550_DE_IRQ_VSYNC,
 895                                .err_mask = MALIDP_DE_IRQ_UNDERRUN |
 896                                            MALIDP650_DE_IRQ_DRIFT |
 897                                            MALIDP550_DE_IRQ_SATURATION |
 898                                            MALIDP550_DE_IRQ_AXI_ERR |
 899                                            MALIDP650_DE_IRQ_ACEV1 |
 900                                            MALIDP650_DE_IRQ_ACEV2 |
 901                                            MALIDP650_DE_IRQ_ACEG |
 902                                            MALIDP650_DE_IRQ_AXIEP,
 903                        },
 904                        .se_irq_map = {
 905                                .irq_mask = MALIDP550_SE_IRQ_EOW,
 906                                .vsync_irq = MALIDP550_SE_IRQ_EOW,
 907                                .err_mask = MALIDP550_SE_IRQ_AXI_ERR |
 908                                            MALIDP550_SE_IRQ_OVR |
 909                                            MALIDP550_SE_IRQ_IBSY,
 910                        },
 911                        .dc_irq_map = {
 912                                .irq_mask = MALIDP550_DC_IRQ_CONF_VALID |
 913                                            MALIDP550_DC_IRQ_SE,
 914                                .vsync_irq = MALIDP550_DC_IRQ_CONF_VALID,
 915                        },
 916                        .pixel_formats = malidp650_de_formats,
 917                        .n_pixel_formats = ARRAY_SIZE(malidp650_de_formats),
 918                        .bus_align_bytes = 16,
 919                },
 920                .query_hw = malidp650_query_hw,
 921                .enter_config_mode = malidp550_enter_config_mode,
 922                .leave_config_mode = malidp550_leave_config_mode,
 923                .in_config_mode = malidp550_in_config_mode,
 924                .set_config_valid = malidp550_set_config_valid,
 925                .modeset = malidp550_modeset,
 926                .rotmem_required = malidp550_rotmem_required,
 927                .se_set_scaling_coeffs = malidp550_se_set_scaling_coeffs,
 928                .se_calc_mclk = malidp550_se_calc_mclk,
 929                .enable_memwrite = malidp550_enable_memwrite,
 930                .disable_memwrite = malidp550_disable_memwrite,
 931                .features = 0,
 932        },
 933};
 934
 935u8 malidp_hw_get_format_id(const struct malidp_hw_regmap *map,
 936                           u8 layer_id, u32 format)
 937{
 938        unsigned int i;
 939
 940        for (i = 0; i < map->n_pixel_formats; i++) {
 941                if (((map->pixel_formats[i].layer & layer_id) == layer_id) &&
 942                    (map->pixel_formats[i].format == format))
 943                        return map->pixel_formats[i].id;
 944        }
 945
 946        return MALIDP_INVALID_FORMAT_ID;
 947}
 948
 949static void malidp_hw_clear_irq(struct malidp_hw_device *hwdev, u8 block, u32 irq)
 950{
 951        u32 base = malidp_get_block_base(hwdev, block);
 952
 953        if (hwdev->hw->map.features & MALIDP_REGMAP_HAS_CLEARIRQ)
 954                malidp_hw_write(hwdev, irq, base + MALIDP_REG_CLEARIRQ);
 955        else
 956                malidp_hw_write(hwdev, irq, base + MALIDP_REG_STATUS);
 957}
 958
 959static irqreturn_t malidp_de_irq(int irq, void *arg)
 960{
 961        struct drm_device *drm = arg;
 962        struct malidp_drm *malidp = drm->dev_private;
 963        struct malidp_hw_device *hwdev;
 964        struct malidp_hw *hw;
 965        const struct malidp_irq_map *de;
 966        u32 status, mask, dc_status;
 967        irqreturn_t ret = IRQ_NONE;
 968
 969        hwdev = malidp->dev;
 970        hw = hwdev->hw;
 971        de = &hw->map.de_irq_map;
 972
 973        /*
 974         * if we are suspended it is likely that we were invoked because
 975         * we share an interrupt line with some other driver, don't try
 976         * to read the hardware registers
 977         */
 978        if (hwdev->pm_suspended)
 979                return IRQ_NONE;
 980
 981        /* first handle the config valid IRQ */
 982        dc_status = malidp_hw_read(hwdev, hw->map.dc_base + MALIDP_REG_STATUS);
 983        if (dc_status & hw->map.dc_irq_map.vsync_irq) {
 984                malidp_hw_clear_irq(hwdev, MALIDP_DC_BLOCK, dc_status);
 985                /* do we have a page flip event? */
 986                if (malidp->event != NULL) {
 987                        spin_lock(&drm->event_lock);
 988                        drm_crtc_send_vblank_event(&malidp->crtc, malidp->event);
 989                        malidp->event = NULL;
 990                        spin_unlock(&drm->event_lock);
 991                }
 992                atomic_set(&malidp->config_valid, MALIDP_CONFIG_VALID_DONE);
 993                ret = IRQ_WAKE_THREAD;
 994        }
 995
 996        status = malidp_hw_read(hwdev, MALIDP_REG_STATUS);
 997        if (!(status & de->irq_mask))
 998                return ret;
 999
1000        mask = malidp_hw_read(hwdev, MALIDP_REG_MASKIRQ);
1001        /* keep the status of the enabled interrupts, plus the error bits */
1002        status &= (mask | de->err_mask);
1003        if ((status & de->vsync_irq) && malidp->crtc.enabled)
1004                drm_crtc_handle_vblank(&malidp->crtc);
1005
1006#ifdef CONFIG_DEBUG_FS
1007        if (status & de->err_mask) {
1008                malidp_error(malidp, &malidp->de_errors, status,
1009                             drm_crtc_vblank_count(&malidp->crtc));
1010        }
1011#endif
1012        malidp_hw_clear_irq(hwdev, MALIDP_DE_BLOCK, status);
1013
1014        return (ret == IRQ_NONE) ? IRQ_HANDLED : ret;
1015}
1016
1017static irqreturn_t malidp_de_irq_thread_handler(int irq, void *arg)
1018{
1019        struct drm_device *drm = arg;
1020        struct malidp_drm *malidp = drm->dev_private;
1021
1022        wake_up(&malidp->wq);
1023
1024        return IRQ_HANDLED;
1025}
1026
1027void malidp_de_irq_hw_init(struct malidp_hw_device *hwdev)
1028{
1029        /* ensure interrupts are disabled */
1030        malidp_hw_disable_irq(hwdev, MALIDP_DE_BLOCK, 0xffffffff);
1031        malidp_hw_clear_irq(hwdev, MALIDP_DE_BLOCK, 0xffffffff);
1032        malidp_hw_disable_irq(hwdev, MALIDP_DC_BLOCK, 0xffffffff);
1033        malidp_hw_clear_irq(hwdev, MALIDP_DC_BLOCK, 0xffffffff);
1034
1035        /* first enable the DC block IRQs */
1036        malidp_hw_enable_irq(hwdev, MALIDP_DC_BLOCK,
1037                             hwdev->hw->map.dc_irq_map.irq_mask);
1038
1039        /* now enable the DE block IRQs */
1040        malidp_hw_enable_irq(hwdev, MALIDP_DE_BLOCK,
1041                             hwdev->hw->map.de_irq_map.irq_mask);
1042}
1043
1044int malidp_de_irq_init(struct drm_device *drm, int irq)
1045{
1046        struct malidp_drm *malidp = drm->dev_private;
1047        struct malidp_hw_device *hwdev = malidp->dev;
1048        int ret;
1049
1050        /* ensure interrupts are disabled */
1051        malidp_hw_disable_irq(hwdev, MALIDP_DE_BLOCK, 0xffffffff);
1052        malidp_hw_clear_irq(hwdev, MALIDP_DE_BLOCK, 0xffffffff);
1053        malidp_hw_disable_irq(hwdev, MALIDP_DC_BLOCK, 0xffffffff);
1054        malidp_hw_clear_irq(hwdev, MALIDP_DC_BLOCK, 0xffffffff);
1055
1056        ret = devm_request_threaded_irq(drm->dev, irq, malidp_de_irq,
1057                                        malidp_de_irq_thread_handler,
1058                                        IRQF_SHARED, "malidp-de", drm);
1059        if (ret < 0) {
1060                DRM_ERROR("failed to install DE IRQ handler\n");
1061                return ret;
1062        }
1063
1064        malidp_de_irq_hw_init(hwdev);
1065
1066        return 0;
1067}
1068
1069void malidp_de_irq_fini(struct malidp_hw_device *hwdev)
1070{
1071        malidp_hw_disable_irq(hwdev, MALIDP_DE_BLOCK,
1072                              hwdev->hw->map.de_irq_map.irq_mask);
1073        malidp_hw_disable_irq(hwdev, MALIDP_DC_BLOCK,
1074                              hwdev->hw->map.dc_irq_map.irq_mask);
1075}
1076
1077static irqreturn_t malidp_se_irq(int irq, void *arg)
1078{
1079        struct drm_device *drm = arg;
1080        struct malidp_drm *malidp = drm->dev_private;
1081        struct malidp_hw_device *hwdev = malidp->dev;
1082        struct malidp_hw *hw = hwdev->hw;
1083        const struct malidp_irq_map *se = &hw->map.se_irq_map;
1084        u32 status, mask;
1085
1086        /*
1087         * if we are suspended it is likely that we were invoked because
1088         * we share an interrupt line with some other driver, don't try
1089         * to read the hardware registers
1090         */
1091        if (hwdev->pm_suspended)
1092                return IRQ_NONE;
1093
1094        status = malidp_hw_read(hwdev, hw->map.se_base + MALIDP_REG_STATUS);
1095        if (!(status & (se->irq_mask | se->err_mask)))
1096                return IRQ_NONE;
1097
1098#ifdef CONFIG_DEBUG_FS
1099        if (status & se->err_mask)
1100                malidp_error(malidp, &malidp->se_errors, status,
1101                             drm_crtc_vblank_count(&malidp->crtc));
1102#endif
1103        mask = malidp_hw_read(hwdev, hw->map.se_base + MALIDP_REG_MASKIRQ);
1104        status &= mask;
1105
1106        if (status & se->vsync_irq) {
1107                switch (hwdev->mw_state) {
1108                case MW_ONESHOT:
1109                        drm_writeback_signal_completion(&malidp->mw_connector, 0);
1110                        break;
1111                case MW_STOP:
1112                        drm_writeback_signal_completion(&malidp->mw_connector, 0);
1113                        /* disable writeback after stop */
1114                        hwdev->mw_state = MW_NOT_ENABLED;
1115                        break;
1116                case MW_RESTART:
1117                        drm_writeback_signal_completion(&malidp->mw_connector, 0);
1118                        /* fall through to a new start */
1119                case MW_START:
1120                        /* writeback started, need to emulate one-shot mode */
1121                        hw->disable_memwrite(hwdev);
1122                        /*
1123                         * only set config_valid HW bit if there is no other update
1124                         * in progress or if we raced ahead of the DE IRQ handler
1125                         * and config_valid flag will not be update until later
1126                         */
1127                        status = malidp_hw_read(hwdev, hw->map.dc_base + MALIDP_REG_STATUS);
1128                        if ((atomic_read(&malidp->config_valid) != MALIDP_CONFIG_START) ||
1129                            (status & hw->map.dc_irq_map.vsync_irq))
1130                                hw->set_config_valid(hwdev, 1);
1131                        break;
1132                }
1133        }
1134
1135        malidp_hw_clear_irq(hwdev, MALIDP_SE_BLOCK, status);
1136
1137        return IRQ_HANDLED;
1138}
1139
1140void malidp_se_irq_hw_init(struct malidp_hw_device *hwdev)
1141{
1142        /* ensure interrupts are disabled */
1143        malidp_hw_disable_irq(hwdev, MALIDP_SE_BLOCK, 0xffffffff);
1144        malidp_hw_clear_irq(hwdev, MALIDP_SE_BLOCK, 0xffffffff);
1145
1146        malidp_hw_enable_irq(hwdev, MALIDP_SE_BLOCK,
1147                             hwdev->hw->map.se_irq_map.irq_mask);
1148}
1149
1150static irqreturn_t malidp_se_irq_thread_handler(int irq, void *arg)
1151{
1152        return IRQ_HANDLED;
1153}
1154
1155int malidp_se_irq_init(struct drm_device *drm, int irq)
1156{
1157        struct malidp_drm *malidp = drm->dev_private;
1158        struct malidp_hw_device *hwdev = malidp->dev;
1159        int ret;
1160
1161        /* ensure interrupts are disabled */
1162        malidp_hw_disable_irq(hwdev, MALIDP_SE_BLOCK, 0xffffffff);
1163        malidp_hw_clear_irq(hwdev, MALIDP_SE_BLOCK, 0xffffffff);
1164
1165        ret = devm_request_threaded_irq(drm->dev, irq, malidp_se_irq,
1166                                        malidp_se_irq_thread_handler,
1167                                        IRQF_SHARED, "malidp-se", drm);
1168        if (ret < 0) {
1169                DRM_ERROR("failed to install SE IRQ handler\n");
1170                return ret;
1171        }
1172
1173        hwdev->mw_state = MW_NOT_ENABLED;
1174        malidp_se_irq_hw_init(hwdev);
1175
1176        return 0;
1177}
1178
1179void malidp_se_irq_fini(struct malidp_hw_device *hwdev)
1180{
1181        malidp_hw_disable_irq(hwdev, MALIDP_SE_BLOCK,
1182                              hwdev->hw->map.se_irq_map.irq_mask);
1183}
1184