162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * (C) COPYRIGHT 2016 ARM Limited. All rights reserved. 462306a36Sopenharmony_ci * Author: Liviu Dudau <Liviu.Dudau@arm.com> 562306a36Sopenharmony_ci * 662306a36Sopenharmony_ci * ARM Mali DP500/DP550/DP650 hardware manipulation routines. This is where 762306a36Sopenharmony_ci * the difference between various versions of the hardware is being dealt with 862306a36Sopenharmony_ci * in an attempt to provide to the rest of the driver code a unified view 962306a36Sopenharmony_ci */ 1062306a36Sopenharmony_ci 1162306a36Sopenharmony_ci#include <linux/clk.h> 1262306a36Sopenharmony_ci#include <linux/delay.h> 1362306a36Sopenharmony_ci#include <linux/types.h> 1462306a36Sopenharmony_ci#include <linux/io.h> 1562306a36Sopenharmony_ci 1662306a36Sopenharmony_ci#include <video/videomode.h> 1762306a36Sopenharmony_ci#include <video/display_timing.h> 1862306a36Sopenharmony_ci 1962306a36Sopenharmony_ci#include <drm/drm_fourcc.h> 2062306a36Sopenharmony_ci#include <drm/drm_vblank.h> 2162306a36Sopenharmony_ci#include <drm/drm_print.h> 2262306a36Sopenharmony_ci 2362306a36Sopenharmony_ci#include "malidp_drv.h" 2462306a36Sopenharmony_ci#include "malidp_hw.h" 2562306a36Sopenharmony_ci#include "malidp_mw.h" 2662306a36Sopenharmony_ci 2762306a36Sopenharmony_cienum { 2862306a36Sopenharmony_ci MW_NOT_ENABLED = 0, /* SE writeback not enabled */ 2962306a36Sopenharmony_ci MW_ONESHOT, /* SE in one-shot mode for writeback */ 3062306a36Sopenharmony_ci MW_START, /* SE started writeback */ 3162306a36Sopenharmony_ci MW_RESTART, /* SE will start another writeback after this one */ 3262306a36Sopenharmony_ci MW_STOP, /* SE needs to stop after this writeback */ 3362306a36Sopenharmony_ci}; 3462306a36Sopenharmony_ci 3562306a36Sopenharmony_cistatic const struct malidp_format_id malidp500_de_formats[] = { 3662306a36Sopenharmony_ci /* fourcc, layers supporting the format, internal id */ 3762306a36Sopenharmony_ci { DRM_FORMAT_ARGB2101010, DE_VIDEO1 | DE_GRAPHICS1 | DE_GRAPHICS2 | SE_MEMWRITE, 0 }, 3862306a36Sopenharmony_ci { DRM_FORMAT_ABGR2101010, DE_VIDEO1 | DE_GRAPHICS1 | DE_GRAPHICS2 | SE_MEMWRITE, 1 }, 3962306a36Sopenharmony_ci { DRM_FORMAT_ARGB8888, DE_VIDEO1 | DE_GRAPHICS1 | DE_GRAPHICS2, 2 }, 4062306a36Sopenharmony_ci { DRM_FORMAT_ABGR8888, DE_VIDEO1 | DE_GRAPHICS1 | DE_GRAPHICS2, 3 }, 4162306a36Sopenharmony_ci { DRM_FORMAT_XRGB8888, DE_VIDEO1 | DE_GRAPHICS1 | DE_GRAPHICS2 | SE_MEMWRITE, 4 }, 4262306a36Sopenharmony_ci { DRM_FORMAT_XBGR8888, DE_VIDEO1 | DE_GRAPHICS1 | DE_GRAPHICS2 | SE_MEMWRITE, 5 }, 4362306a36Sopenharmony_ci { DRM_FORMAT_RGB888, DE_VIDEO1 | DE_GRAPHICS1 | DE_GRAPHICS2, 6 }, 4462306a36Sopenharmony_ci { DRM_FORMAT_BGR888, DE_VIDEO1 | DE_GRAPHICS1 | DE_GRAPHICS2, 7 }, 4562306a36Sopenharmony_ci { DRM_FORMAT_RGBA5551, DE_VIDEO1 | DE_GRAPHICS1 | DE_GRAPHICS2, 8 }, 4662306a36Sopenharmony_ci { DRM_FORMAT_ABGR1555, DE_VIDEO1 | DE_GRAPHICS1 | DE_GRAPHICS2, 9 }, 4762306a36Sopenharmony_ci { DRM_FORMAT_RGB565, DE_VIDEO1 | DE_GRAPHICS1 | DE_GRAPHICS2, 10 }, 4862306a36Sopenharmony_ci { DRM_FORMAT_BGR565, DE_VIDEO1 | DE_GRAPHICS1 | DE_GRAPHICS2, 11 }, 4962306a36Sopenharmony_ci { DRM_FORMAT_UYVY, DE_VIDEO1, 12 }, 5062306a36Sopenharmony_ci { DRM_FORMAT_YUYV, DE_VIDEO1, 13 }, 5162306a36Sopenharmony_ci { DRM_FORMAT_NV12, DE_VIDEO1 | SE_MEMWRITE, 14 }, 5262306a36Sopenharmony_ci { DRM_FORMAT_YUV420, DE_VIDEO1, 15 }, 5362306a36Sopenharmony_ci { DRM_FORMAT_XYUV8888, DE_VIDEO1, 16 }, 5462306a36Sopenharmony_ci /* These are supported with AFBC only */ 5562306a36Sopenharmony_ci { DRM_FORMAT_YUV420_8BIT, DE_VIDEO1, 14 }, 5662306a36Sopenharmony_ci { DRM_FORMAT_VUY888, DE_VIDEO1, 16 }, 5762306a36Sopenharmony_ci { DRM_FORMAT_VUY101010, DE_VIDEO1, 17 }, 5862306a36Sopenharmony_ci { DRM_FORMAT_YUV420_10BIT, DE_VIDEO1, 18 } 5962306a36Sopenharmony_ci}; 6062306a36Sopenharmony_ci 6162306a36Sopenharmony_ci#define MALIDP_ID(__group, __format) \ 6262306a36Sopenharmony_ci ((((__group) & 0x7) << 3) | ((__format) & 0x7)) 6362306a36Sopenharmony_ci 6462306a36Sopenharmony_ci#define AFBC_YUV_422_FORMAT_ID MALIDP_ID(5, 1) 6562306a36Sopenharmony_ci 6662306a36Sopenharmony_ci#define MALIDP_COMMON_FORMATS \ 6762306a36Sopenharmony_ci /* fourcc, layers supporting the format, internal id */ \ 6862306a36Sopenharmony_ci { DRM_FORMAT_ARGB2101010, DE_VIDEO1 | DE_GRAPHICS1 | DE_VIDEO2 | SE_MEMWRITE, MALIDP_ID(0, 0) }, \ 6962306a36Sopenharmony_ci { DRM_FORMAT_ABGR2101010, DE_VIDEO1 | DE_GRAPHICS1 | DE_VIDEO2 | SE_MEMWRITE, MALIDP_ID(0, 1) }, \ 7062306a36Sopenharmony_ci { DRM_FORMAT_RGBA1010102, DE_VIDEO1 | DE_GRAPHICS1 | DE_VIDEO2 | SE_MEMWRITE, MALIDP_ID(0, 2) }, \ 7162306a36Sopenharmony_ci { DRM_FORMAT_BGRA1010102, DE_VIDEO1 | DE_GRAPHICS1 | DE_VIDEO2 | SE_MEMWRITE, MALIDP_ID(0, 3) }, \ 7262306a36Sopenharmony_ci { DRM_FORMAT_ARGB8888, DE_VIDEO1 | DE_GRAPHICS1 | DE_VIDEO2 | DE_SMART, MALIDP_ID(1, 0) }, \ 7362306a36Sopenharmony_ci { DRM_FORMAT_ABGR8888, DE_VIDEO1 | DE_GRAPHICS1 | DE_VIDEO2 | DE_SMART, MALIDP_ID(1, 1) }, \ 7462306a36Sopenharmony_ci { DRM_FORMAT_RGBA8888, DE_VIDEO1 | DE_GRAPHICS1 | DE_VIDEO2 | DE_SMART, MALIDP_ID(1, 2) }, \ 7562306a36Sopenharmony_ci { DRM_FORMAT_BGRA8888, DE_VIDEO1 | DE_GRAPHICS1 | DE_VIDEO2 | DE_SMART, MALIDP_ID(1, 3) }, \ 7662306a36Sopenharmony_ci { DRM_FORMAT_XRGB8888, DE_VIDEO1 | DE_GRAPHICS1 | DE_VIDEO2 | DE_SMART | SE_MEMWRITE, MALIDP_ID(2, 0) }, \ 7762306a36Sopenharmony_ci { DRM_FORMAT_XBGR8888, DE_VIDEO1 | DE_GRAPHICS1 | DE_VIDEO2 | DE_SMART | SE_MEMWRITE, MALIDP_ID(2, 1) }, \ 7862306a36Sopenharmony_ci { DRM_FORMAT_RGBX8888, DE_VIDEO1 | DE_GRAPHICS1 | DE_VIDEO2 | DE_SMART | SE_MEMWRITE, MALIDP_ID(2, 2) }, \ 7962306a36Sopenharmony_ci { DRM_FORMAT_BGRX8888, DE_VIDEO1 | DE_GRAPHICS1 | DE_VIDEO2 | DE_SMART | SE_MEMWRITE, MALIDP_ID(2, 3) }, \ 8062306a36Sopenharmony_ci { DRM_FORMAT_RGB888, DE_VIDEO1 | DE_GRAPHICS1 | DE_VIDEO2 | SE_MEMWRITE, MALIDP_ID(3, 0) }, \ 8162306a36Sopenharmony_ci { DRM_FORMAT_BGR888, DE_VIDEO1 | DE_GRAPHICS1 | DE_VIDEO2 | SE_MEMWRITE, MALIDP_ID(3, 1) }, \ 8262306a36Sopenharmony_ci { DRM_FORMAT_RGBA5551, DE_VIDEO1 | DE_GRAPHICS1 | DE_VIDEO2, MALIDP_ID(4, 0) }, \ 8362306a36Sopenharmony_ci { DRM_FORMAT_ABGR1555, DE_VIDEO1 | DE_GRAPHICS1 | DE_VIDEO2, MALIDP_ID(4, 1) }, \ 8462306a36Sopenharmony_ci { DRM_FORMAT_RGB565, DE_VIDEO1 | DE_GRAPHICS1 | DE_VIDEO2, MALIDP_ID(4, 2) }, \ 8562306a36Sopenharmony_ci { DRM_FORMAT_BGR565, DE_VIDEO1 | DE_GRAPHICS1 | DE_VIDEO2, MALIDP_ID(4, 3) }, \ 8662306a36Sopenharmony_ci /* This is only supported with linear modifier */ \ 8762306a36Sopenharmony_ci { DRM_FORMAT_XYUV8888, DE_VIDEO1 | DE_VIDEO2, MALIDP_ID(5, 0) },\ 8862306a36Sopenharmony_ci /* This is only supported with AFBC modifier */ \ 8962306a36Sopenharmony_ci { DRM_FORMAT_VUY888, DE_VIDEO1 | DE_VIDEO2, MALIDP_ID(5, 0) }, \ 9062306a36Sopenharmony_ci { DRM_FORMAT_YUYV, DE_VIDEO1 | DE_VIDEO2, MALIDP_ID(5, 2) }, \ 9162306a36Sopenharmony_ci /* This is only supported with linear modifier */ \ 9262306a36Sopenharmony_ci { DRM_FORMAT_UYVY, DE_VIDEO1 | DE_VIDEO2, MALIDP_ID(5, 3) }, \ 9362306a36Sopenharmony_ci { DRM_FORMAT_NV12, DE_VIDEO1 | DE_VIDEO2 | SE_MEMWRITE, MALIDP_ID(5, 6) }, \ 9462306a36Sopenharmony_ci /* This is only supported with AFBC modifier */ \ 9562306a36Sopenharmony_ci { DRM_FORMAT_YUV420_8BIT, DE_VIDEO1 | DE_VIDEO2, MALIDP_ID(5, 6) }, \ 9662306a36Sopenharmony_ci { DRM_FORMAT_YUV420, DE_VIDEO1 | DE_VIDEO2, MALIDP_ID(5, 7) }, \ 9762306a36Sopenharmony_ci /* This is only supported with linear modifier */ \ 9862306a36Sopenharmony_ci { DRM_FORMAT_XVYU2101010, DE_VIDEO1 | DE_VIDEO2, MALIDP_ID(6, 0)}, \ 9962306a36Sopenharmony_ci /* This is only supported with AFBC modifier */ \ 10062306a36Sopenharmony_ci { DRM_FORMAT_VUY101010, DE_VIDEO1 | DE_VIDEO2, MALIDP_ID(6, 0)}, \ 10162306a36Sopenharmony_ci { DRM_FORMAT_X0L2, DE_VIDEO1 | DE_VIDEO2, MALIDP_ID(6, 6)}, \ 10262306a36Sopenharmony_ci /* This is only supported with AFBC modifier */ \ 10362306a36Sopenharmony_ci { DRM_FORMAT_YUV420_10BIT, DE_VIDEO1 | DE_VIDEO2, MALIDP_ID(6, 7)}, \ 10462306a36Sopenharmony_ci { DRM_FORMAT_P010, DE_VIDEO1 | DE_VIDEO2, MALIDP_ID(6, 7)} 10562306a36Sopenharmony_ci 10662306a36Sopenharmony_cistatic const struct malidp_format_id malidp550_de_formats[] = { 10762306a36Sopenharmony_ci MALIDP_COMMON_FORMATS, 10862306a36Sopenharmony_ci}; 10962306a36Sopenharmony_ci 11062306a36Sopenharmony_cistatic const struct malidp_format_id malidp650_de_formats[] = { 11162306a36Sopenharmony_ci MALIDP_COMMON_FORMATS, 11262306a36Sopenharmony_ci { DRM_FORMAT_X0L0, DE_VIDEO1 | DE_VIDEO2, MALIDP_ID(5, 4)}, 11362306a36Sopenharmony_ci}; 11462306a36Sopenharmony_ci 11562306a36Sopenharmony_cistatic const struct malidp_layer malidp500_layers[] = { 11662306a36Sopenharmony_ci /* id, base address, fb pointer address base, stride offset, 11762306a36Sopenharmony_ci * yuv2rgb matrix offset, mmu control register offset, rotation_features 11862306a36Sopenharmony_ci */ 11962306a36Sopenharmony_ci { DE_VIDEO1, MALIDP500_DE_LV_BASE, MALIDP500_DE_LV_PTR_BASE, 12062306a36Sopenharmony_ci MALIDP_DE_LV_STRIDE0, MALIDP500_LV_YUV2RGB, 0, ROTATE_ANY, 12162306a36Sopenharmony_ci MALIDP500_DE_LV_AD_CTRL }, 12262306a36Sopenharmony_ci { DE_GRAPHICS1, MALIDP500_DE_LG1_BASE, MALIDP500_DE_LG1_PTR_BASE, 12362306a36Sopenharmony_ci MALIDP_DE_LG_STRIDE, 0, 0, ROTATE_ANY, 12462306a36Sopenharmony_ci MALIDP500_DE_LG1_AD_CTRL }, 12562306a36Sopenharmony_ci { DE_GRAPHICS2, MALIDP500_DE_LG2_BASE, MALIDP500_DE_LG2_PTR_BASE, 12662306a36Sopenharmony_ci MALIDP_DE_LG_STRIDE, 0, 0, ROTATE_ANY, 12762306a36Sopenharmony_ci MALIDP500_DE_LG2_AD_CTRL }, 12862306a36Sopenharmony_ci}; 12962306a36Sopenharmony_ci 13062306a36Sopenharmony_cistatic const struct malidp_layer malidp550_layers[] = { 13162306a36Sopenharmony_ci /* id, base address, fb pointer address base, stride offset, 13262306a36Sopenharmony_ci * yuv2rgb matrix offset, mmu control register offset, rotation_features 13362306a36Sopenharmony_ci */ 13462306a36Sopenharmony_ci { DE_VIDEO1, MALIDP550_DE_LV1_BASE, MALIDP550_DE_LV1_PTR_BASE, 13562306a36Sopenharmony_ci MALIDP_DE_LV_STRIDE0, MALIDP550_LV_YUV2RGB, 0, ROTATE_ANY, 13662306a36Sopenharmony_ci MALIDP550_DE_LV1_AD_CTRL }, 13762306a36Sopenharmony_ci { DE_GRAPHICS1, MALIDP550_DE_LG_BASE, MALIDP550_DE_LG_PTR_BASE, 13862306a36Sopenharmony_ci MALIDP_DE_LG_STRIDE, 0, 0, ROTATE_ANY, 13962306a36Sopenharmony_ci MALIDP550_DE_LG_AD_CTRL }, 14062306a36Sopenharmony_ci { DE_VIDEO2, MALIDP550_DE_LV2_BASE, MALIDP550_DE_LV2_PTR_BASE, 14162306a36Sopenharmony_ci MALIDP_DE_LV_STRIDE0, MALIDP550_LV_YUV2RGB, 0, ROTATE_ANY, 14262306a36Sopenharmony_ci MALIDP550_DE_LV2_AD_CTRL }, 14362306a36Sopenharmony_ci { DE_SMART, MALIDP550_DE_LS_BASE, MALIDP550_DE_LS_PTR_BASE, 14462306a36Sopenharmony_ci MALIDP550_DE_LS_R1_STRIDE, 0, 0, ROTATE_NONE, 0 }, 14562306a36Sopenharmony_ci}; 14662306a36Sopenharmony_ci 14762306a36Sopenharmony_cistatic const struct malidp_layer malidp650_layers[] = { 14862306a36Sopenharmony_ci /* id, base address, fb pointer address base, stride offset, 14962306a36Sopenharmony_ci * yuv2rgb matrix offset, mmu control register offset, 15062306a36Sopenharmony_ci * rotation_features 15162306a36Sopenharmony_ci */ 15262306a36Sopenharmony_ci { DE_VIDEO1, MALIDP550_DE_LV1_BASE, MALIDP550_DE_LV1_PTR_BASE, 15362306a36Sopenharmony_ci MALIDP_DE_LV_STRIDE0, MALIDP550_LV_YUV2RGB, 15462306a36Sopenharmony_ci MALIDP650_DE_LV_MMU_CTRL, ROTATE_ANY, 15562306a36Sopenharmony_ci MALIDP550_DE_LV1_AD_CTRL }, 15662306a36Sopenharmony_ci { DE_GRAPHICS1, MALIDP550_DE_LG_BASE, MALIDP550_DE_LG_PTR_BASE, 15762306a36Sopenharmony_ci MALIDP_DE_LG_STRIDE, 0, MALIDP650_DE_LG_MMU_CTRL, 15862306a36Sopenharmony_ci ROTATE_COMPRESSED, MALIDP550_DE_LG_AD_CTRL }, 15962306a36Sopenharmony_ci { DE_VIDEO2, MALIDP550_DE_LV2_BASE, MALIDP550_DE_LV2_PTR_BASE, 16062306a36Sopenharmony_ci MALIDP_DE_LV_STRIDE0, MALIDP550_LV_YUV2RGB, 16162306a36Sopenharmony_ci MALIDP650_DE_LV_MMU_CTRL, ROTATE_ANY, 16262306a36Sopenharmony_ci MALIDP550_DE_LV2_AD_CTRL }, 16362306a36Sopenharmony_ci { DE_SMART, MALIDP550_DE_LS_BASE, MALIDP550_DE_LS_PTR_BASE, 16462306a36Sopenharmony_ci MALIDP550_DE_LS_R1_STRIDE, 0, MALIDP650_DE_LS_MMU_CTRL, 16562306a36Sopenharmony_ci ROTATE_NONE, 0 }, 16662306a36Sopenharmony_ci}; 16762306a36Sopenharmony_ci 16862306a36Sopenharmony_ciconst u64 malidp_format_modifiers[] = { 16962306a36Sopenharmony_ci /* All RGB formats (except XRGB, RGBX, XBGR, BGRX) */ 17062306a36Sopenharmony_ci DRM_FORMAT_MOD_ARM_AFBC(AFBC_SIZE_16X16 | AFBC_YTR | AFBC_SPARSE), 17162306a36Sopenharmony_ci DRM_FORMAT_MOD_ARM_AFBC(AFBC_SIZE_16X16 | AFBC_YTR), 17262306a36Sopenharmony_ci 17362306a36Sopenharmony_ci /* All RGB formats > 16bpp (except XRGB, RGBX, XBGR, BGRX) */ 17462306a36Sopenharmony_ci DRM_FORMAT_MOD_ARM_AFBC(AFBC_SIZE_16X16 | AFBC_YTR | AFBC_SPARSE | AFBC_SPLIT), 17562306a36Sopenharmony_ci 17662306a36Sopenharmony_ci /* All 8 or 10 bit YUV 444 formats. */ 17762306a36Sopenharmony_ci /* In DP550, 10 bit YUV 420 format also supported */ 17862306a36Sopenharmony_ci DRM_FORMAT_MOD_ARM_AFBC(AFBC_SIZE_16X16 | AFBC_SPARSE | AFBC_SPLIT), 17962306a36Sopenharmony_ci 18062306a36Sopenharmony_ci /* YUV 420, 422 P1 8 bit and YUV 444 8 bit/10 bit formats */ 18162306a36Sopenharmony_ci DRM_FORMAT_MOD_ARM_AFBC(AFBC_SIZE_16X16 | AFBC_SPARSE), 18262306a36Sopenharmony_ci DRM_FORMAT_MOD_ARM_AFBC(AFBC_SIZE_16X16), 18362306a36Sopenharmony_ci 18462306a36Sopenharmony_ci /* YUV 420, 422 P1 8, 10 bit formats */ 18562306a36Sopenharmony_ci DRM_FORMAT_MOD_ARM_AFBC(AFBC_SIZE_16X16 | AFBC_CBR | AFBC_SPARSE), 18662306a36Sopenharmony_ci DRM_FORMAT_MOD_ARM_AFBC(AFBC_SIZE_16X16 | AFBC_CBR), 18762306a36Sopenharmony_ci 18862306a36Sopenharmony_ci /* All formats */ 18962306a36Sopenharmony_ci DRM_FORMAT_MOD_LINEAR, 19062306a36Sopenharmony_ci 19162306a36Sopenharmony_ci DRM_FORMAT_MOD_INVALID 19262306a36Sopenharmony_ci}; 19362306a36Sopenharmony_ci 19462306a36Sopenharmony_ci#define SE_N_SCALING_COEFFS 96 19562306a36Sopenharmony_cistatic const u16 dp500_se_scaling_coeffs[][SE_N_SCALING_COEFFS] = { 19662306a36Sopenharmony_ci [MALIDP_UPSCALING_COEFFS - 1] = { 19762306a36Sopenharmony_ci 0x0000, 0x0001, 0x0007, 0x0011, 0x001e, 0x002e, 0x003f, 0x0052, 19862306a36Sopenharmony_ci 0x0064, 0x0073, 0x007d, 0x0080, 0x007a, 0x006c, 0x0053, 0x002f, 19962306a36Sopenharmony_ci 0x0000, 0x3fc6, 0x3f83, 0x3f39, 0x3eea, 0x3e9b, 0x3e4f, 0x3e0a, 20062306a36Sopenharmony_ci 0x3dd4, 0x3db0, 0x3da2, 0x3db1, 0x3dde, 0x3e2f, 0x3ea5, 0x3f40, 20162306a36Sopenharmony_ci 0x0000, 0x00e5, 0x01ee, 0x0315, 0x0456, 0x05aa, 0x0709, 0x086c, 20262306a36Sopenharmony_ci 0x09c9, 0x0b15, 0x0c4a, 0x0d5d, 0x0e4a, 0x0f06, 0x0f91, 0x0fe5, 20362306a36Sopenharmony_ci 0x1000, 0x0fe5, 0x0f91, 0x0f06, 0x0e4a, 0x0d5d, 0x0c4a, 0x0b15, 20462306a36Sopenharmony_ci 0x09c9, 0x086c, 0x0709, 0x05aa, 0x0456, 0x0315, 0x01ee, 0x00e5, 20562306a36Sopenharmony_ci 0x0000, 0x3f40, 0x3ea5, 0x3e2f, 0x3dde, 0x3db1, 0x3da2, 0x3db0, 20662306a36Sopenharmony_ci 0x3dd4, 0x3e0a, 0x3e4f, 0x3e9b, 0x3eea, 0x3f39, 0x3f83, 0x3fc6, 20762306a36Sopenharmony_ci 0x0000, 0x002f, 0x0053, 0x006c, 0x007a, 0x0080, 0x007d, 0x0073, 20862306a36Sopenharmony_ci 0x0064, 0x0052, 0x003f, 0x002e, 0x001e, 0x0011, 0x0007, 0x0001 20962306a36Sopenharmony_ci }, 21062306a36Sopenharmony_ci [MALIDP_DOWNSCALING_1_5_COEFFS - 1] = { 21162306a36Sopenharmony_ci 0x0059, 0x004f, 0x0041, 0x002e, 0x0016, 0x3ffb, 0x3fd9, 0x3fb4, 21262306a36Sopenharmony_ci 0x3f8c, 0x3f62, 0x3f36, 0x3f09, 0x3edd, 0x3eb3, 0x3e8d, 0x3e6c, 21362306a36Sopenharmony_ci 0x3e52, 0x3e3f, 0x3e35, 0x3e37, 0x3e46, 0x3e61, 0x3e8c, 0x3ec5, 21462306a36Sopenharmony_ci 0x3f0f, 0x3f68, 0x3fd1, 0x004a, 0x00d3, 0x0169, 0x020b, 0x02b8, 21562306a36Sopenharmony_ci 0x036e, 0x042d, 0x04f2, 0x05b9, 0x0681, 0x0745, 0x0803, 0x08ba, 21662306a36Sopenharmony_ci 0x0965, 0x0a03, 0x0a91, 0x0b0d, 0x0b75, 0x0bc6, 0x0c00, 0x0c20, 21762306a36Sopenharmony_ci 0x0c28, 0x0c20, 0x0c00, 0x0bc6, 0x0b75, 0x0b0d, 0x0a91, 0x0a03, 21862306a36Sopenharmony_ci 0x0965, 0x08ba, 0x0803, 0x0745, 0x0681, 0x05b9, 0x04f2, 0x042d, 21962306a36Sopenharmony_ci 0x036e, 0x02b8, 0x020b, 0x0169, 0x00d3, 0x004a, 0x3fd1, 0x3f68, 22062306a36Sopenharmony_ci 0x3f0f, 0x3ec5, 0x3e8c, 0x3e61, 0x3e46, 0x3e37, 0x3e35, 0x3e3f, 22162306a36Sopenharmony_ci 0x3e52, 0x3e6c, 0x3e8d, 0x3eb3, 0x3edd, 0x3f09, 0x3f36, 0x3f62, 22262306a36Sopenharmony_ci 0x3f8c, 0x3fb4, 0x3fd9, 0x3ffb, 0x0016, 0x002e, 0x0041, 0x004f 22362306a36Sopenharmony_ci }, 22462306a36Sopenharmony_ci [MALIDP_DOWNSCALING_2_COEFFS - 1] = { 22562306a36Sopenharmony_ci 0x3f19, 0x3f03, 0x3ef0, 0x3edf, 0x3ed0, 0x3ec5, 0x3ebd, 0x3eb9, 22662306a36Sopenharmony_ci 0x3eb9, 0x3ebf, 0x3eca, 0x3ed9, 0x3eef, 0x3f0a, 0x3f2c, 0x3f52, 22762306a36Sopenharmony_ci 0x3f7f, 0x3fb0, 0x3fe8, 0x0026, 0x006a, 0x00b4, 0x0103, 0x0158, 22862306a36Sopenharmony_ci 0x01b1, 0x020d, 0x026c, 0x02cd, 0x032f, 0x0392, 0x03f4, 0x0455, 22962306a36Sopenharmony_ci 0x04b4, 0x051e, 0x0585, 0x05eb, 0x064c, 0x06a8, 0x06fe, 0x074e, 23062306a36Sopenharmony_ci 0x0796, 0x07d5, 0x080c, 0x0839, 0x085c, 0x0875, 0x0882, 0x0887, 23162306a36Sopenharmony_ci 0x0881, 0x0887, 0x0882, 0x0875, 0x085c, 0x0839, 0x080c, 0x07d5, 23262306a36Sopenharmony_ci 0x0796, 0x074e, 0x06fe, 0x06a8, 0x064c, 0x05eb, 0x0585, 0x051e, 23362306a36Sopenharmony_ci 0x04b4, 0x0455, 0x03f4, 0x0392, 0x032f, 0x02cd, 0x026c, 0x020d, 23462306a36Sopenharmony_ci 0x01b1, 0x0158, 0x0103, 0x00b4, 0x006a, 0x0026, 0x3fe8, 0x3fb0, 23562306a36Sopenharmony_ci 0x3f7f, 0x3f52, 0x3f2c, 0x3f0a, 0x3eef, 0x3ed9, 0x3eca, 0x3ebf, 23662306a36Sopenharmony_ci 0x3eb9, 0x3eb9, 0x3ebd, 0x3ec5, 0x3ed0, 0x3edf, 0x3ef0, 0x3f03 23762306a36Sopenharmony_ci }, 23862306a36Sopenharmony_ci [MALIDP_DOWNSCALING_2_75_COEFFS - 1] = { 23962306a36Sopenharmony_ci 0x3f51, 0x3f60, 0x3f71, 0x3f84, 0x3f98, 0x3faf, 0x3fc8, 0x3fe3, 24062306a36Sopenharmony_ci 0x0000, 0x001f, 0x0040, 0x0064, 0x008a, 0x00b1, 0x00da, 0x0106, 24162306a36Sopenharmony_ci 0x0133, 0x0160, 0x018e, 0x01bd, 0x01ec, 0x021d, 0x024e, 0x0280, 24262306a36Sopenharmony_ci 0x02b2, 0x02e4, 0x0317, 0x0349, 0x037c, 0x03ad, 0x03df, 0x0410, 24362306a36Sopenharmony_ci 0x0440, 0x0468, 0x048f, 0x04b3, 0x04d6, 0x04f8, 0x0516, 0x0533, 24462306a36Sopenharmony_ci 0x054e, 0x0566, 0x057c, 0x0590, 0x05a0, 0x05ae, 0x05ba, 0x05c3, 24562306a36Sopenharmony_ci 0x05c9, 0x05c3, 0x05ba, 0x05ae, 0x05a0, 0x0590, 0x057c, 0x0566, 24662306a36Sopenharmony_ci 0x054e, 0x0533, 0x0516, 0x04f8, 0x04d6, 0x04b3, 0x048f, 0x0468, 24762306a36Sopenharmony_ci 0x0440, 0x0410, 0x03df, 0x03ad, 0x037c, 0x0349, 0x0317, 0x02e4, 24862306a36Sopenharmony_ci 0x02b2, 0x0280, 0x024e, 0x021d, 0x01ec, 0x01bd, 0x018e, 0x0160, 24962306a36Sopenharmony_ci 0x0133, 0x0106, 0x00da, 0x00b1, 0x008a, 0x0064, 0x0040, 0x001f, 25062306a36Sopenharmony_ci 0x0000, 0x3fe3, 0x3fc8, 0x3faf, 0x3f98, 0x3f84, 0x3f71, 0x3f60 25162306a36Sopenharmony_ci }, 25262306a36Sopenharmony_ci [MALIDP_DOWNSCALING_4_COEFFS - 1] = { 25362306a36Sopenharmony_ci 0x0094, 0x00a9, 0x00be, 0x00d4, 0x00ea, 0x0101, 0x0118, 0x012f, 25462306a36Sopenharmony_ci 0x0148, 0x0160, 0x017a, 0x0193, 0x01ae, 0x01c8, 0x01e4, 0x01ff, 25562306a36Sopenharmony_ci 0x021c, 0x0233, 0x024a, 0x0261, 0x0278, 0x028f, 0x02a6, 0x02bd, 25662306a36Sopenharmony_ci 0x02d4, 0x02eb, 0x0302, 0x0319, 0x032f, 0x0346, 0x035d, 0x0374, 25762306a36Sopenharmony_ci 0x038a, 0x0397, 0x03a3, 0x03af, 0x03bb, 0x03c6, 0x03d1, 0x03db, 25862306a36Sopenharmony_ci 0x03e4, 0x03ed, 0x03f6, 0x03fe, 0x0406, 0x040d, 0x0414, 0x041a, 25962306a36Sopenharmony_ci 0x0420, 0x041a, 0x0414, 0x040d, 0x0406, 0x03fe, 0x03f6, 0x03ed, 26062306a36Sopenharmony_ci 0x03e4, 0x03db, 0x03d1, 0x03c6, 0x03bb, 0x03af, 0x03a3, 0x0397, 26162306a36Sopenharmony_ci 0x038a, 0x0374, 0x035d, 0x0346, 0x032f, 0x0319, 0x0302, 0x02eb, 26262306a36Sopenharmony_ci 0x02d4, 0x02bd, 0x02a6, 0x028f, 0x0278, 0x0261, 0x024a, 0x0233, 26362306a36Sopenharmony_ci 0x021c, 0x01ff, 0x01e4, 0x01c8, 0x01ae, 0x0193, 0x017a, 0x0160, 26462306a36Sopenharmony_ci 0x0148, 0x012f, 0x0118, 0x0101, 0x00ea, 0x00d4, 0x00be, 0x00a9 26562306a36Sopenharmony_ci }, 26662306a36Sopenharmony_ci}; 26762306a36Sopenharmony_ci 26862306a36Sopenharmony_ci#define MALIDP_DE_DEFAULT_PREFETCH_START 5 26962306a36Sopenharmony_ci 27062306a36Sopenharmony_cistatic int malidp500_query_hw(struct malidp_hw_device *hwdev) 27162306a36Sopenharmony_ci{ 27262306a36Sopenharmony_ci u32 conf = malidp_hw_read(hwdev, MALIDP500_CONFIG_ID); 27362306a36Sopenharmony_ci /* bit 4 of the CONFIG_ID register holds the line size multiplier */ 27462306a36Sopenharmony_ci u8 ln_size_mult = conf & 0x10 ? 2 : 1; 27562306a36Sopenharmony_ci 27662306a36Sopenharmony_ci hwdev->min_line_size = 2; 27762306a36Sopenharmony_ci hwdev->max_line_size = SZ_2K * ln_size_mult; 27862306a36Sopenharmony_ci hwdev->rotation_memory[0] = SZ_1K * 64 * ln_size_mult; 27962306a36Sopenharmony_ci hwdev->rotation_memory[1] = 0; /* no second rotation memory bank */ 28062306a36Sopenharmony_ci 28162306a36Sopenharmony_ci return 0; 28262306a36Sopenharmony_ci} 28362306a36Sopenharmony_ci 28462306a36Sopenharmony_cistatic void malidp500_enter_config_mode(struct malidp_hw_device *hwdev) 28562306a36Sopenharmony_ci{ 28662306a36Sopenharmony_ci u32 status, count = 100; 28762306a36Sopenharmony_ci 28862306a36Sopenharmony_ci malidp_hw_setbits(hwdev, MALIDP500_DC_CONFIG_REQ, MALIDP500_DC_CONTROL); 28962306a36Sopenharmony_ci while (count) { 29062306a36Sopenharmony_ci status = malidp_hw_read(hwdev, hwdev->hw->map.dc_base + MALIDP_REG_STATUS); 29162306a36Sopenharmony_ci if ((status & MALIDP500_DC_CONFIG_REQ) == MALIDP500_DC_CONFIG_REQ) 29262306a36Sopenharmony_ci break; 29362306a36Sopenharmony_ci /* 29462306a36Sopenharmony_ci * entering config mode can take as long as the rendering 29562306a36Sopenharmony_ci * of a full frame, hence the long sleep here 29662306a36Sopenharmony_ci */ 29762306a36Sopenharmony_ci usleep_range(1000, 10000); 29862306a36Sopenharmony_ci count--; 29962306a36Sopenharmony_ci } 30062306a36Sopenharmony_ci WARN(count == 0, "timeout while entering config mode"); 30162306a36Sopenharmony_ci} 30262306a36Sopenharmony_ci 30362306a36Sopenharmony_cistatic void malidp500_leave_config_mode(struct malidp_hw_device *hwdev) 30462306a36Sopenharmony_ci{ 30562306a36Sopenharmony_ci u32 status, count = 100; 30662306a36Sopenharmony_ci 30762306a36Sopenharmony_ci malidp_hw_clearbits(hwdev, MALIDP_CFG_VALID, MALIDP500_CONFIG_VALID); 30862306a36Sopenharmony_ci malidp_hw_clearbits(hwdev, MALIDP500_DC_CONFIG_REQ, MALIDP500_DC_CONTROL); 30962306a36Sopenharmony_ci while (count) { 31062306a36Sopenharmony_ci status = malidp_hw_read(hwdev, hwdev->hw->map.dc_base + MALIDP_REG_STATUS); 31162306a36Sopenharmony_ci if ((status & MALIDP500_DC_CONFIG_REQ) == 0) 31262306a36Sopenharmony_ci break; 31362306a36Sopenharmony_ci usleep_range(100, 1000); 31462306a36Sopenharmony_ci count--; 31562306a36Sopenharmony_ci } 31662306a36Sopenharmony_ci WARN(count == 0, "timeout while leaving config mode"); 31762306a36Sopenharmony_ci} 31862306a36Sopenharmony_ci 31962306a36Sopenharmony_cistatic bool malidp500_in_config_mode(struct malidp_hw_device *hwdev) 32062306a36Sopenharmony_ci{ 32162306a36Sopenharmony_ci u32 status; 32262306a36Sopenharmony_ci 32362306a36Sopenharmony_ci status = malidp_hw_read(hwdev, hwdev->hw->map.dc_base + MALIDP_REG_STATUS); 32462306a36Sopenharmony_ci if ((status & MALIDP500_DC_CONFIG_REQ) == MALIDP500_DC_CONFIG_REQ) 32562306a36Sopenharmony_ci return true; 32662306a36Sopenharmony_ci 32762306a36Sopenharmony_ci return false; 32862306a36Sopenharmony_ci} 32962306a36Sopenharmony_ci 33062306a36Sopenharmony_cistatic void malidp500_set_config_valid(struct malidp_hw_device *hwdev, u8 value) 33162306a36Sopenharmony_ci{ 33262306a36Sopenharmony_ci if (value) 33362306a36Sopenharmony_ci malidp_hw_setbits(hwdev, MALIDP_CFG_VALID, MALIDP500_CONFIG_VALID); 33462306a36Sopenharmony_ci else 33562306a36Sopenharmony_ci malidp_hw_clearbits(hwdev, MALIDP_CFG_VALID, MALIDP500_CONFIG_VALID); 33662306a36Sopenharmony_ci} 33762306a36Sopenharmony_ci 33862306a36Sopenharmony_cistatic void malidp500_modeset(struct malidp_hw_device *hwdev, struct videomode *mode) 33962306a36Sopenharmony_ci{ 34062306a36Sopenharmony_ci u32 val = 0; 34162306a36Sopenharmony_ci 34262306a36Sopenharmony_ci malidp_hw_write(hwdev, hwdev->output_color_depth, 34362306a36Sopenharmony_ci hwdev->hw->map.out_depth_base); 34462306a36Sopenharmony_ci malidp_hw_clearbits(hwdev, MALIDP500_DC_CLEAR_MASK, MALIDP500_DC_CONTROL); 34562306a36Sopenharmony_ci if (mode->flags & DISPLAY_FLAGS_HSYNC_HIGH) 34662306a36Sopenharmony_ci val |= MALIDP500_HSYNCPOL; 34762306a36Sopenharmony_ci if (mode->flags & DISPLAY_FLAGS_VSYNC_HIGH) 34862306a36Sopenharmony_ci val |= MALIDP500_VSYNCPOL; 34962306a36Sopenharmony_ci val |= MALIDP_DE_DEFAULT_PREFETCH_START; 35062306a36Sopenharmony_ci malidp_hw_setbits(hwdev, val, MALIDP500_DC_CONTROL); 35162306a36Sopenharmony_ci 35262306a36Sopenharmony_ci /* 35362306a36Sopenharmony_ci * Mali-DP500 encodes the background color like this: 35462306a36Sopenharmony_ci * - red @ MALIDP500_BGND_COLOR[12:0] 35562306a36Sopenharmony_ci * - green @ MALIDP500_BGND_COLOR[27:16] 35662306a36Sopenharmony_ci * - blue @ (MALIDP500_BGND_COLOR + 4)[12:0] 35762306a36Sopenharmony_ci */ 35862306a36Sopenharmony_ci val = ((MALIDP_BGND_COLOR_G & 0xfff) << 16) | 35962306a36Sopenharmony_ci (MALIDP_BGND_COLOR_R & 0xfff); 36062306a36Sopenharmony_ci malidp_hw_write(hwdev, val, MALIDP500_BGND_COLOR); 36162306a36Sopenharmony_ci malidp_hw_write(hwdev, MALIDP_BGND_COLOR_B, MALIDP500_BGND_COLOR + 4); 36262306a36Sopenharmony_ci 36362306a36Sopenharmony_ci val = MALIDP_DE_H_FRONTPORCH(mode->hfront_porch) | 36462306a36Sopenharmony_ci MALIDP_DE_H_BACKPORCH(mode->hback_porch); 36562306a36Sopenharmony_ci malidp_hw_write(hwdev, val, MALIDP500_TIMINGS_BASE + MALIDP_DE_H_TIMINGS); 36662306a36Sopenharmony_ci 36762306a36Sopenharmony_ci val = MALIDP500_DE_V_FRONTPORCH(mode->vfront_porch) | 36862306a36Sopenharmony_ci MALIDP_DE_V_BACKPORCH(mode->vback_porch); 36962306a36Sopenharmony_ci malidp_hw_write(hwdev, val, MALIDP500_TIMINGS_BASE + MALIDP_DE_V_TIMINGS); 37062306a36Sopenharmony_ci 37162306a36Sopenharmony_ci val = MALIDP_DE_H_SYNCWIDTH(mode->hsync_len) | 37262306a36Sopenharmony_ci MALIDP_DE_V_SYNCWIDTH(mode->vsync_len); 37362306a36Sopenharmony_ci malidp_hw_write(hwdev, val, MALIDP500_TIMINGS_BASE + MALIDP_DE_SYNC_WIDTH); 37462306a36Sopenharmony_ci 37562306a36Sopenharmony_ci val = MALIDP_DE_H_ACTIVE(mode->hactive) | MALIDP_DE_V_ACTIVE(mode->vactive); 37662306a36Sopenharmony_ci malidp_hw_write(hwdev, val, MALIDP500_TIMINGS_BASE + MALIDP_DE_HV_ACTIVE); 37762306a36Sopenharmony_ci 37862306a36Sopenharmony_ci if (mode->flags & DISPLAY_FLAGS_INTERLACED) 37962306a36Sopenharmony_ci malidp_hw_setbits(hwdev, MALIDP_DISP_FUNC_ILACED, MALIDP_DE_DISPLAY_FUNC); 38062306a36Sopenharmony_ci else 38162306a36Sopenharmony_ci malidp_hw_clearbits(hwdev, MALIDP_DISP_FUNC_ILACED, MALIDP_DE_DISPLAY_FUNC); 38262306a36Sopenharmony_ci 38362306a36Sopenharmony_ci /* 38462306a36Sopenharmony_ci * Program the RQoS register to avoid high resolutions flicker 38562306a36Sopenharmony_ci * issue on the LS1028A. 38662306a36Sopenharmony_ci */ 38762306a36Sopenharmony_ci if (hwdev->arqos_value) { 38862306a36Sopenharmony_ci val = hwdev->arqos_value; 38962306a36Sopenharmony_ci malidp_hw_setbits(hwdev, val, MALIDP500_RQOS_QUALITY); 39062306a36Sopenharmony_ci } 39162306a36Sopenharmony_ci} 39262306a36Sopenharmony_ci 39362306a36Sopenharmony_ciint malidp_format_get_bpp(u32 fmt) 39462306a36Sopenharmony_ci{ 39562306a36Sopenharmony_ci const struct drm_format_info *info = drm_format_info(fmt); 39662306a36Sopenharmony_ci int bpp = info->cpp[0] * 8; 39762306a36Sopenharmony_ci 39862306a36Sopenharmony_ci if (bpp == 0) { 39962306a36Sopenharmony_ci switch (fmt) { 40062306a36Sopenharmony_ci case DRM_FORMAT_VUY101010: 40162306a36Sopenharmony_ci bpp = 30; 40262306a36Sopenharmony_ci break; 40362306a36Sopenharmony_ci case DRM_FORMAT_YUV420_10BIT: 40462306a36Sopenharmony_ci bpp = 15; 40562306a36Sopenharmony_ci break; 40662306a36Sopenharmony_ci case DRM_FORMAT_YUV420_8BIT: 40762306a36Sopenharmony_ci bpp = 12; 40862306a36Sopenharmony_ci break; 40962306a36Sopenharmony_ci default: 41062306a36Sopenharmony_ci bpp = 0; 41162306a36Sopenharmony_ci } 41262306a36Sopenharmony_ci } 41362306a36Sopenharmony_ci 41462306a36Sopenharmony_ci return bpp; 41562306a36Sopenharmony_ci} 41662306a36Sopenharmony_ci 41762306a36Sopenharmony_cistatic int malidp500_rotmem_required(struct malidp_hw_device *hwdev, u16 w, 41862306a36Sopenharmony_ci u16 h, u32 fmt, bool has_modifier) 41962306a36Sopenharmony_ci{ 42062306a36Sopenharmony_ci /* 42162306a36Sopenharmony_ci * Each layer needs enough rotation memory to fit 8 lines 42262306a36Sopenharmony_ci * worth of pixel data. Required size is then: 42362306a36Sopenharmony_ci * size = rotated_width * (bpp / 8) * 8; 42462306a36Sopenharmony_ci */ 42562306a36Sopenharmony_ci int bpp = malidp_format_get_bpp(fmt); 42662306a36Sopenharmony_ci 42762306a36Sopenharmony_ci return w * bpp; 42862306a36Sopenharmony_ci} 42962306a36Sopenharmony_ci 43062306a36Sopenharmony_cistatic void malidp500_se_write_pp_coefftab(struct malidp_hw_device *hwdev, 43162306a36Sopenharmony_ci u32 direction, 43262306a36Sopenharmony_ci u16 addr, 43362306a36Sopenharmony_ci u8 coeffs_id) 43462306a36Sopenharmony_ci{ 43562306a36Sopenharmony_ci int i; 43662306a36Sopenharmony_ci u16 scaling_control = MALIDP500_SE_CONTROL + MALIDP_SE_SCALING_CONTROL; 43762306a36Sopenharmony_ci 43862306a36Sopenharmony_ci malidp_hw_write(hwdev, 43962306a36Sopenharmony_ci direction | (addr & MALIDP_SE_COEFFTAB_ADDR_MASK), 44062306a36Sopenharmony_ci scaling_control + MALIDP_SE_COEFFTAB_ADDR); 44162306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(dp500_se_scaling_coeffs); ++i) 44262306a36Sopenharmony_ci malidp_hw_write(hwdev, MALIDP_SE_SET_COEFFTAB_DATA( 44362306a36Sopenharmony_ci dp500_se_scaling_coeffs[coeffs_id][i]), 44462306a36Sopenharmony_ci scaling_control + MALIDP_SE_COEFFTAB_DATA); 44562306a36Sopenharmony_ci} 44662306a36Sopenharmony_ci 44762306a36Sopenharmony_cistatic int malidp500_se_set_scaling_coeffs(struct malidp_hw_device *hwdev, 44862306a36Sopenharmony_ci struct malidp_se_config *se_config, 44962306a36Sopenharmony_ci struct malidp_se_config *old_config) 45062306a36Sopenharmony_ci{ 45162306a36Sopenharmony_ci /* Get array indices into dp500_se_scaling_coeffs. */ 45262306a36Sopenharmony_ci u8 h = (u8)se_config->hcoeff - 1; 45362306a36Sopenharmony_ci u8 v = (u8)se_config->vcoeff - 1; 45462306a36Sopenharmony_ci 45562306a36Sopenharmony_ci if (WARN_ON(h >= ARRAY_SIZE(dp500_se_scaling_coeffs) || 45662306a36Sopenharmony_ci v >= ARRAY_SIZE(dp500_se_scaling_coeffs))) 45762306a36Sopenharmony_ci return -EINVAL; 45862306a36Sopenharmony_ci 45962306a36Sopenharmony_ci if ((h == v) && (se_config->hcoeff != old_config->hcoeff || 46062306a36Sopenharmony_ci se_config->vcoeff != old_config->vcoeff)) { 46162306a36Sopenharmony_ci malidp500_se_write_pp_coefftab(hwdev, 46262306a36Sopenharmony_ci (MALIDP_SE_V_COEFFTAB | 46362306a36Sopenharmony_ci MALIDP_SE_H_COEFFTAB), 46462306a36Sopenharmony_ci 0, v); 46562306a36Sopenharmony_ci } else { 46662306a36Sopenharmony_ci if (se_config->vcoeff != old_config->vcoeff) 46762306a36Sopenharmony_ci malidp500_se_write_pp_coefftab(hwdev, 46862306a36Sopenharmony_ci MALIDP_SE_V_COEFFTAB, 46962306a36Sopenharmony_ci 0, v); 47062306a36Sopenharmony_ci if (se_config->hcoeff != old_config->hcoeff) 47162306a36Sopenharmony_ci malidp500_se_write_pp_coefftab(hwdev, 47262306a36Sopenharmony_ci MALIDP_SE_H_COEFFTAB, 47362306a36Sopenharmony_ci 0, h); 47462306a36Sopenharmony_ci } 47562306a36Sopenharmony_ci 47662306a36Sopenharmony_ci return 0; 47762306a36Sopenharmony_ci} 47862306a36Sopenharmony_ci 47962306a36Sopenharmony_cistatic long malidp500_se_calc_mclk(struct malidp_hw_device *hwdev, 48062306a36Sopenharmony_ci struct malidp_se_config *se_config, 48162306a36Sopenharmony_ci struct videomode *vm) 48262306a36Sopenharmony_ci{ 48362306a36Sopenharmony_ci unsigned long mclk; 48462306a36Sopenharmony_ci unsigned long pxlclk = vm->pixelclock; /* Hz */ 48562306a36Sopenharmony_ci unsigned long htotal = vm->hactive + vm->hfront_porch + 48662306a36Sopenharmony_ci vm->hback_porch + vm->hsync_len; 48762306a36Sopenharmony_ci unsigned long input_size = se_config->input_w * se_config->input_h; 48862306a36Sopenharmony_ci unsigned long a = 10; 48962306a36Sopenharmony_ci long ret; 49062306a36Sopenharmony_ci 49162306a36Sopenharmony_ci /* 49262306a36Sopenharmony_ci * mclk = max(a, 1.5) * pxlclk 49362306a36Sopenharmony_ci * 49462306a36Sopenharmony_ci * To avoid float calculaiton, using 15 instead of 1.5 and div by 49562306a36Sopenharmony_ci * 10 to get mclk. 49662306a36Sopenharmony_ci */ 49762306a36Sopenharmony_ci if (se_config->scale_enable) { 49862306a36Sopenharmony_ci a = 15 * input_size / (htotal * se_config->output_h); 49962306a36Sopenharmony_ci if (a < 15) 50062306a36Sopenharmony_ci a = 15; 50162306a36Sopenharmony_ci } 50262306a36Sopenharmony_ci mclk = a * pxlclk / 10; 50362306a36Sopenharmony_ci ret = clk_get_rate(hwdev->mclk); 50462306a36Sopenharmony_ci if (ret < mclk) { 50562306a36Sopenharmony_ci DRM_DEBUG_DRIVER("mclk requirement of %lu kHz can't be met.\n", 50662306a36Sopenharmony_ci mclk / 1000); 50762306a36Sopenharmony_ci return -EINVAL; 50862306a36Sopenharmony_ci } 50962306a36Sopenharmony_ci return ret; 51062306a36Sopenharmony_ci} 51162306a36Sopenharmony_ci 51262306a36Sopenharmony_cistatic int malidp500_enable_memwrite(struct malidp_hw_device *hwdev, 51362306a36Sopenharmony_ci dma_addr_t *addrs, s32 *pitches, 51462306a36Sopenharmony_ci int num_planes, u16 w, u16 h, u32 fmt_id, 51562306a36Sopenharmony_ci const s16 *rgb2yuv_coeffs) 51662306a36Sopenharmony_ci{ 51762306a36Sopenharmony_ci u32 base = MALIDP500_SE_MEMWRITE_BASE; 51862306a36Sopenharmony_ci u32 de_base = malidp_get_block_base(hwdev, MALIDP_DE_BLOCK); 51962306a36Sopenharmony_ci 52062306a36Sopenharmony_ci /* enable the scaling engine block */ 52162306a36Sopenharmony_ci malidp_hw_setbits(hwdev, MALIDP_SCALE_ENGINE_EN, de_base + MALIDP_DE_DISPLAY_FUNC); 52262306a36Sopenharmony_ci 52362306a36Sopenharmony_ci /* restart the writeback if already enabled */ 52462306a36Sopenharmony_ci if (hwdev->mw_state != MW_NOT_ENABLED) 52562306a36Sopenharmony_ci hwdev->mw_state = MW_RESTART; 52662306a36Sopenharmony_ci else 52762306a36Sopenharmony_ci hwdev->mw_state = MW_START; 52862306a36Sopenharmony_ci 52962306a36Sopenharmony_ci malidp_hw_write(hwdev, fmt_id, base + MALIDP_MW_FORMAT); 53062306a36Sopenharmony_ci switch (num_planes) { 53162306a36Sopenharmony_ci case 2: 53262306a36Sopenharmony_ci malidp_hw_write(hwdev, lower_32_bits(addrs[1]), base + MALIDP_MW_P2_PTR_LOW); 53362306a36Sopenharmony_ci malidp_hw_write(hwdev, upper_32_bits(addrs[1]), base + MALIDP_MW_P2_PTR_HIGH); 53462306a36Sopenharmony_ci malidp_hw_write(hwdev, pitches[1], base + MALIDP_MW_P2_STRIDE); 53562306a36Sopenharmony_ci fallthrough; 53662306a36Sopenharmony_ci case 1: 53762306a36Sopenharmony_ci malidp_hw_write(hwdev, lower_32_bits(addrs[0]), base + MALIDP_MW_P1_PTR_LOW); 53862306a36Sopenharmony_ci malidp_hw_write(hwdev, upper_32_bits(addrs[0]), base + MALIDP_MW_P1_PTR_HIGH); 53962306a36Sopenharmony_ci malidp_hw_write(hwdev, pitches[0], base + MALIDP_MW_P1_STRIDE); 54062306a36Sopenharmony_ci break; 54162306a36Sopenharmony_ci default: 54262306a36Sopenharmony_ci WARN(1, "Invalid number of planes"); 54362306a36Sopenharmony_ci } 54462306a36Sopenharmony_ci 54562306a36Sopenharmony_ci malidp_hw_write(hwdev, MALIDP_DE_H_ACTIVE(w) | MALIDP_DE_V_ACTIVE(h), 54662306a36Sopenharmony_ci MALIDP500_SE_MEMWRITE_OUT_SIZE); 54762306a36Sopenharmony_ci 54862306a36Sopenharmony_ci if (rgb2yuv_coeffs) { 54962306a36Sopenharmony_ci int i; 55062306a36Sopenharmony_ci 55162306a36Sopenharmony_ci for (i = 0; i < MALIDP_COLORADJ_NUM_COEFFS; i++) { 55262306a36Sopenharmony_ci malidp_hw_write(hwdev, rgb2yuv_coeffs[i], 55362306a36Sopenharmony_ci MALIDP500_SE_RGB_YUV_COEFFS + i * 4); 55462306a36Sopenharmony_ci } 55562306a36Sopenharmony_ci } 55662306a36Sopenharmony_ci 55762306a36Sopenharmony_ci malidp_hw_setbits(hwdev, MALIDP_SE_MEMWRITE_EN, MALIDP500_SE_CONTROL); 55862306a36Sopenharmony_ci 55962306a36Sopenharmony_ci return 0; 56062306a36Sopenharmony_ci} 56162306a36Sopenharmony_ci 56262306a36Sopenharmony_cistatic void malidp500_disable_memwrite(struct malidp_hw_device *hwdev) 56362306a36Sopenharmony_ci{ 56462306a36Sopenharmony_ci u32 base = malidp_get_block_base(hwdev, MALIDP_DE_BLOCK); 56562306a36Sopenharmony_ci 56662306a36Sopenharmony_ci if (hwdev->mw_state == MW_START || hwdev->mw_state == MW_RESTART) 56762306a36Sopenharmony_ci hwdev->mw_state = MW_STOP; 56862306a36Sopenharmony_ci malidp_hw_clearbits(hwdev, MALIDP_SE_MEMWRITE_EN, MALIDP500_SE_CONTROL); 56962306a36Sopenharmony_ci malidp_hw_clearbits(hwdev, MALIDP_SCALE_ENGINE_EN, base + MALIDP_DE_DISPLAY_FUNC); 57062306a36Sopenharmony_ci} 57162306a36Sopenharmony_ci 57262306a36Sopenharmony_cistatic int malidp550_query_hw(struct malidp_hw_device *hwdev) 57362306a36Sopenharmony_ci{ 57462306a36Sopenharmony_ci u32 conf = malidp_hw_read(hwdev, MALIDP550_CONFIG_ID); 57562306a36Sopenharmony_ci u8 ln_size = (conf >> 4) & 0x3, rsize; 57662306a36Sopenharmony_ci 57762306a36Sopenharmony_ci hwdev->min_line_size = 2; 57862306a36Sopenharmony_ci 57962306a36Sopenharmony_ci switch (ln_size) { 58062306a36Sopenharmony_ci case 0: 58162306a36Sopenharmony_ci hwdev->max_line_size = SZ_2K; 58262306a36Sopenharmony_ci /* two banks of 64KB for rotation memory */ 58362306a36Sopenharmony_ci rsize = 64; 58462306a36Sopenharmony_ci break; 58562306a36Sopenharmony_ci case 1: 58662306a36Sopenharmony_ci hwdev->max_line_size = SZ_4K; 58762306a36Sopenharmony_ci /* two banks of 128KB for rotation memory */ 58862306a36Sopenharmony_ci rsize = 128; 58962306a36Sopenharmony_ci break; 59062306a36Sopenharmony_ci case 2: 59162306a36Sopenharmony_ci hwdev->max_line_size = 1280; 59262306a36Sopenharmony_ci /* two banks of 40KB for rotation memory */ 59362306a36Sopenharmony_ci rsize = 40; 59462306a36Sopenharmony_ci break; 59562306a36Sopenharmony_ci case 3: 59662306a36Sopenharmony_ci /* reserved value */ 59762306a36Sopenharmony_ci hwdev->max_line_size = 0; 59862306a36Sopenharmony_ci return -EINVAL; 59962306a36Sopenharmony_ci } 60062306a36Sopenharmony_ci 60162306a36Sopenharmony_ci hwdev->rotation_memory[0] = hwdev->rotation_memory[1] = rsize * SZ_1K; 60262306a36Sopenharmony_ci return 0; 60362306a36Sopenharmony_ci} 60462306a36Sopenharmony_ci 60562306a36Sopenharmony_cistatic void malidp550_enter_config_mode(struct malidp_hw_device *hwdev) 60662306a36Sopenharmony_ci{ 60762306a36Sopenharmony_ci u32 status, count = 100; 60862306a36Sopenharmony_ci 60962306a36Sopenharmony_ci malidp_hw_setbits(hwdev, MALIDP550_DC_CONFIG_REQ, MALIDP550_DC_CONTROL); 61062306a36Sopenharmony_ci while (count) { 61162306a36Sopenharmony_ci status = malidp_hw_read(hwdev, hwdev->hw->map.dc_base + MALIDP_REG_STATUS); 61262306a36Sopenharmony_ci if ((status & MALIDP550_DC_CONFIG_REQ) == MALIDP550_DC_CONFIG_REQ) 61362306a36Sopenharmony_ci break; 61462306a36Sopenharmony_ci /* 61562306a36Sopenharmony_ci * entering config mode can take as long as the rendering 61662306a36Sopenharmony_ci * of a full frame, hence the long sleep here 61762306a36Sopenharmony_ci */ 61862306a36Sopenharmony_ci usleep_range(1000, 10000); 61962306a36Sopenharmony_ci count--; 62062306a36Sopenharmony_ci } 62162306a36Sopenharmony_ci WARN(count == 0, "timeout while entering config mode"); 62262306a36Sopenharmony_ci} 62362306a36Sopenharmony_ci 62462306a36Sopenharmony_cistatic void malidp550_leave_config_mode(struct malidp_hw_device *hwdev) 62562306a36Sopenharmony_ci{ 62662306a36Sopenharmony_ci u32 status, count = 100; 62762306a36Sopenharmony_ci 62862306a36Sopenharmony_ci malidp_hw_clearbits(hwdev, MALIDP_CFG_VALID, MALIDP550_CONFIG_VALID); 62962306a36Sopenharmony_ci malidp_hw_clearbits(hwdev, MALIDP550_DC_CONFIG_REQ, MALIDP550_DC_CONTROL); 63062306a36Sopenharmony_ci while (count) { 63162306a36Sopenharmony_ci status = malidp_hw_read(hwdev, hwdev->hw->map.dc_base + MALIDP_REG_STATUS); 63262306a36Sopenharmony_ci if ((status & MALIDP550_DC_CONFIG_REQ) == 0) 63362306a36Sopenharmony_ci break; 63462306a36Sopenharmony_ci usleep_range(100, 1000); 63562306a36Sopenharmony_ci count--; 63662306a36Sopenharmony_ci } 63762306a36Sopenharmony_ci WARN(count == 0, "timeout while leaving config mode"); 63862306a36Sopenharmony_ci} 63962306a36Sopenharmony_ci 64062306a36Sopenharmony_cistatic bool malidp550_in_config_mode(struct malidp_hw_device *hwdev) 64162306a36Sopenharmony_ci{ 64262306a36Sopenharmony_ci u32 status; 64362306a36Sopenharmony_ci 64462306a36Sopenharmony_ci status = malidp_hw_read(hwdev, hwdev->hw->map.dc_base + MALIDP_REG_STATUS); 64562306a36Sopenharmony_ci if ((status & MALIDP550_DC_CONFIG_REQ) == MALIDP550_DC_CONFIG_REQ) 64662306a36Sopenharmony_ci return true; 64762306a36Sopenharmony_ci 64862306a36Sopenharmony_ci return false; 64962306a36Sopenharmony_ci} 65062306a36Sopenharmony_ci 65162306a36Sopenharmony_cistatic void malidp550_set_config_valid(struct malidp_hw_device *hwdev, u8 value) 65262306a36Sopenharmony_ci{ 65362306a36Sopenharmony_ci if (value) 65462306a36Sopenharmony_ci malidp_hw_setbits(hwdev, MALIDP_CFG_VALID, MALIDP550_CONFIG_VALID); 65562306a36Sopenharmony_ci else 65662306a36Sopenharmony_ci malidp_hw_clearbits(hwdev, MALIDP_CFG_VALID, MALIDP550_CONFIG_VALID); 65762306a36Sopenharmony_ci} 65862306a36Sopenharmony_ci 65962306a36Sopenharmony_cistatic void malidp550_modeset(struct malidp_hw_device *hwdev, struct videomode *mode) 66062306a36Sopenharmony_ci{ 66162306a36Sopenharmony_ci u32 val = MALIDP_DE_DEFAULT_PREFETCH_START; 66262306a36Sopenharmony_ci 66362306a36Sopenharmony_ci malidp_hw_write(hwdev, hwdev->output_color_depth, 66462306a36Sopenharmony_ci hwdev->hw->map.out_depth_base); 66562306a36Sopenharmony_ci malidp_hw_write(hwdev, val, MALIDP550_DE_CONTROL); 66662306a36Sopenharmony_ci /* 66762306a36Sopenharmony_ci * Mali-DP550 and Mali-DP650 encode the background color like this: 66862306a36Sopenharmony_ci * - red @ MALIDP550_DE_BGND_COLOR[23:16] 66962306a36Sopenharmony_ci * - green @ MALIDP550_DE_BGND_COLOR[15:8] 67062306a36Sopenharmony_ci * - blue @ MALIDP550_DE_BGND_COLOR[7:0] 67162306a36Sopenharmony_ci * 67262306a36Sopenharmony_ci * We need to truncate the least significant 4 bits from the default 67362306a36Sopenharmony_ci * MALIDP_BGND_COLOR_x values 67462306a36Sopenharmony_ci */ 67562306a36Sopenharmony_ci val = (((MALIDP_BGND_COLOR_R >> 4) & 0xff) << 16) | 67662306a36Sopenharmony_ci (((MALIDP_BGND_COLOR_G >> 4) & 0xff) << 8) | 67762306a36Sopenharmony_ci ((MALIDP_BGND_COLOR_B >> 4) & 0xff); 67862306a36Sopenharmony_ci malidp_hw_write(hwdev, val, MALIDP550_DE_BGND_COLOR); 67962306a36Sopenharmony_ci 68062306a36Sopenharmony_ci val = MALIDP_DE_H_FRONTPORCH(mode->hfront_porch) | 68162306a36Sopenharmony_ci MALIDP_DE_H_BACKPORCH(mode->hback_porch); 68262306a36Sopenharmony_ci malidp_hw_write(hwdev, val, MALIDP550_TIMINGS_BASE + MALIDP_DE_H_TIMINGS); 68362306a36Sopenharmony_ci 68462306a36Sopenharmony_ci val = MALIDP550_DE_V_FRONTPORCH(mode->vfront_porch) | 68562306a36Sopenharmony_ci MALIDP_DE_V_BACKPORCH(mode->vback_porch); 68662306a36Sopenharmony_ci malidp_hw_write(hwdev, val, MALIDP550_TIMINGS_BASE + MALIDP_DE_V_TIMINGS); 68762306a36Sopenharmony_ci 68862306a36Sopenharmony_ci val = MALIDP_DE_H_SYNCWIDTH(mode->hsync_len) | 68962306a36Sopenharmony_ci MALIDP_DE_V_SYNCWIDTH(mode->vsync_len); 69062306a36Sopenharmony_ci if (mode->flags & DISPLAY_FLAGS_HSYNC_HIGH) 69162306a36Sopenharmony_ci val |= MALIDP550_HSYNCPOL; 69262306a36Sopenharmony_ci if (mode->flags & DISPLAY_FLAGS_VSYNC_HIGH) 69362306a36Sopenharmony_ci val |= MALIDP550_VSYNCPOL; 69462306a36Sopenharmony_ci malidp_hw_write(hwdev, val, MALIDP550_TIMINGS_BASE + MALIDP_DE_SYNC_WIDTH); 69562306a36Sopenharmony_ci 69662306a36Sopenharmony_ci val = MALIDP_DE_H_ACTIVE(mode->hactive) | MALIDP_DE_V_ACTIVE(mode->vactive); 69762306a36Sopenharmony_ci malidp_hw_write(hwdev, val, MALIDP550_TIMINGS_BASE + MALIDP_DE_HV_ACTIVE); 69862306a36Sopenharmony_ci 69962306a36Sopenharmony_ci if (mode->flags & DISPLAY_FLAGS_INTERLACED) 70062306a36Sopenharmony_ci malidp_hw_setbits(hwdev, MALIDP_DISP_FUNC_ILACED, MALIDP_DE_DISPLAY_FUNC); 70162306a36Sopenharmony_ci else 70262306a36Sopenharmony_ci malidp_hw_clearbits(hwdev, MALIDP_DISP_FUNC_ILACED, MALIDP_DE_DISPLAY_FUNC); 70362306a36Sopenharmony_ci} 70462306a36Sopenharmony_ci 70562306a36Sopenharmony_cistatic int malidpx50_get_bytes_per_column(u32 fmt) 70662306a36Sopenharmony_ci{ 70762306a36Sopenharmony_ci u32 bytes_per_column; 70862306a36Sopenharmony_ci 70962306a36Sopenharmony_ci switch (fmt) { 71062306a36Sopenharmony_ci /* 8 lines at 4 bytes per pixel */ 71162306a36Sopenharmony_ci case DRM_FORMAT_ARGB2101010: 71262306a36Sopenharmony_ci case DRM_FORMAT_ABGR2101010: 71362306a36Sopenharmony_ci case DRM_FORMAT_RGBA1010102: 71462306a36Sopenharmony_ci case DRM_FORMAT_BGRA1010102: 71562306a36Sopenharmony_ci case DRM_FORMAT_ARGB8888: 71662306a36Sopenharmony_ci case DRM_FORMAT_ABGR8888: 71762306a36Sopenharmony_ci case DRM_FORMAT_RGBA8888: 71862306a36Sopenharmony_ci case DRM_FORMAT_BGRA8888: 71962306a36Sopenharmony_ci case DRM_FORMAT_XRGB8888: 72062306a36Sopenharmony_ci case DRM_FORMAT_XBGR8888: 72162306a36Sopenharmony_ci case DRM_FORMAT_RGBX8888: 72262306a36Sopenharmony_ci case DRM_FORMAT_BGRX8888: 72362306a36Sopenharmony_ci case DRM_FORMAT_RGB888: 72462306a36Sopenharmony_ci case DRM_FORMAT_BGR888: 72562306a36Sopenharmony_ci /* 16 lines at 2 bytes per pixel */ 72662306a36Sopenharmony_ci case DRM_FORMAT_RGBA5551: 72762306a36Sopenharmony_ci case DRM_FORMAT_ABGR1555: 72862306a36Sopenharmony_ci case DRM_FORMAT_RGB565: 72962306a36Sopenharmony_ci case DRM_FORMAT_BGR565: 73062306a36Sopenharmony_ci case DRM_FORMAT_UYVY: 73162306a36Sopenharmony_ci case DRM_FORMAT_YUYV: 73262306a36Sopenharmony_ci case DRM_FORMAT_X0L0: 73362306a36Sopenharmony_ci bytes_per_column = 32; 73462306a36Sopenharmony_ci break; 73562306a36Sopenharmony_ci /* 16 lines at 1.5 bytes per pixel */ 73662306a36Sopenharmony_ci case DRM_FORMAT_NV12: 73762306a36Sopenharmony_ci case DRM_FORMAT_YUV420: 73862306a36Sopenharmony_ci /* 8 lines at 3 bytes per pixel */ 73962306a36Sopenharmony_ci case DRM_FORMAT_VUY888: 74062306a36Sopenharmony_ci /* 16 lines at 12 bits per pixel */ 74162306a36Sopenharmony_ci case DRM_FORMAT_YUV420_8BIT: 74262306a36Sopenharmony_ci /* 8 lines at 3 bytes per pixel */ 74362306a36Sopenharmony_ci case DRM_FORMAT_P010: 74462306a36Sopenharmony_ci bytes_per_column = 24; 74562306a36Sopenharmony_ci break; 74662306a36Sopenharmony_ci /* 8 lines at 30 bits per pixel */ 74762306a36Sopenharmony_ci case DRM_FORMAT_VUY101010: 74862306a36Sopenharmony_ci /* 16 lines at 15 bits per pixel */ 74962306a36Sopenharmony_ci case DRM_FORMAT_YUV420_10BIT: 75062306a36Sopenharmony_ci bytes_per_column = 30; 75162306a36Sopenharmony_ci break; 75262306a36Sopenharmony_ci default: 75362306a36Sopenharmony_ci return -EINVAL; 75462306a36Sopenharmony_ci } 75562306a36Sopenharmony_ci 75662306a36Sopenharmony_ci return bytes_per_column; 75762306a36Sopenharmony_ci} 75862306a36Sopenharmony_ci 75962306a36Sopenharmony_cistatic int malidp550_rotmem_required(struct malidp_hw_device *hwdev, u16 w, 76062306a36Sopenharmony_ci u16 h, u32 fmt, bool has_modifier) 76162306a36Sopenharmony_ci{ 76262306a36Sopenharmony_ci int bytes_per_column = 0; 76362306a36Sopenharmony_ci 76462306a36Sopenharmony_ci switch (fmt) { 76562306a36Sopenharmony_ci /* 8 lines at 15 bits per pixel */ 76662306a36Sopenharmony_ci case DRM_FORMAT_YUV420_10BIT: 76762306a36Sopenharmony_ci bytes_per_column = 15; 76862306a36Sopenharmony_ci break; 76962306a36Sopenharmony_ci /* Uncompressed YUV 420 10 bit single plane cannot be rotated */ 77062306a36Sopenharmony_ci case DRM_FORMAT_X0L2: 77162306a36Sopenharmony_ci if (has_modifier) 77262306a36Sopenharmony_ci bytes_per_column = 8; 77362306a36Sopenharmony_ci else 77462306a36Sopenharmony_ci return -EINVAL; 77562306a36Sopenharmony_ci break; 77662306a36Sopenharmony_ci default: 77762306a36Sopenharmony_ci bytes_per_column = malidpx50_get_bytes_per_column(fmt); 77862306a36Sopenharmony_ci } 77962306a36Sopenharmony_ci 78062306a36Sopenharmony_ci if (bytes_per_column == -EINVAL) 78162306a36Sopenharmony_ci return bytes_per_column; 78262306a36Sopenharmony_ci 78362306a36Sopenharmony_ci return w * bytes_per_column; 78462306a36Sopenharmony_ci} 78562306a36Sopenharmony_ci 78662306a36Sopenharmony_cistatic int malidp650_rotmem_required(struct malidp_hw_device *hwdev, u16 w, 78762306a36Sopenharmony_ci u16 h, u32 fmt, bool has_modifier) 78862306a36Sopenharmony_ci{ 78962306a36Sopenharmony_ci int bytes_per_column = 0; 79062306a36Sopenharmony_ci 79162306a36Sopenharmony_ci switch (fmt) { 79262306a36Sopenharmony_ci /* 16 lines at 2 bytes per pixel */ 79362306a36Sopenharmony_ci case DRM_FORMAT_X0L2: 79462306a36Sopenharmony_ci bytes_per_column = 32; 79562306a36Sopenharmony_ci break; 79662306a36Sopenharmony_ci default: 79762306a36Sopenharmony_ci bytes_per_column = malidpx50_get_bytes_per_column(fmt); 79862306a36Sopenharmony_ci } 79962306a36Sopenharmony_ci 80062306a36Sopenharmony_ci if (bytes_per_column == -EINVAL) 80162306a36Sopenharmony_ci return bytes_per_column; 80262306a36Sopenharmony_ci 80362306a36Sopenharmony_ci return w * bytes_per_column; 80462306a36Sopenharmony_ci} 80562306a36Sopenharmony_ci 80662306a36Sopenharmony_cistatic int malidp550_se_set_scaling_coeffs(struct malidp_hw_device *hwdev, 80762306a36Sopenharmony_ci struct malidp_se_config *se_config, 80862306a36Sopenharmony_ci struct malidp_se_config *old_config) 80962306a36Sopenharmony_ci{ 81062306a36Sopenharmony_ci u32 mask = MALIDP550_SE_CTL_VCSEL(MALIDP550_SE_CTL_SEL_MASK) | 81162306a36Sopenharmony_ci MALIDP550_SE_CTL_HCSEL(MALIDP550_SE_CTL_SEL_MASK); 81262306a36Sopenharmony_ci u32 new_value = MALIDP550_SE_CTL_VCSEL(se_config->vcoeff) | 81362306a36Sopenharmony_ci MALIDP550_SE_CTL_HCSEL(se_config->hcoeff); 81462306a36Sopenharmony_ci 81562306a36Sopenharmony_ci malidp_hw_clearbits(hwdev, mask, MALIDP550_SE_CONTROL); 81662306a36Sopenharmony_ci malidp_hw_setbits(hwdev, new_value, MALIDP550_SE_CONTROL); 81762306a36Sopenharmony_ci return 0; 81862306a36Sopenharmony_ci} 81962306a36Sopenharmony_ci 82062306a36Sopenharmony_cistatic long malidp550_se_calc_mclk(struct malidp_hw_device *hwdev, 82162306a36Sopenharmony_ci struct malidp_se_config *se_config, 82262306a36Sopenharmony_ci struct videomode *vm) 82362306a36Sopenharmony_ci{ 82462306a36Sopenharmony_ci unsigned long mclk; 82562306a36Sopenharmony_ci unsigned long pxlclk = vm->pixelclock; 82662306a36Sopenharmony_ci unsigned long htotal = vm->hactive + vm->hfront_porch + 82762306a36Sopenharmony_ci vm->hback_porch + vm->hsync_len; 82862306a36Sopenharmony_ci unsigned long numerator = 1, denominator = 1; 82962306a36Sopenharmony_ci long ret; 83062306a36Sopenharmony_ci 83162306a36Sopenharmony_ci if (se_config->scale_enable) { 83262306a36Sopenharmony_ci numerator = max(se_config->input_w, se_config->output_w) * 83362306a36Sopenharmony_ci se_config->input_h; 83462306a36Sopenharmony_ci numerator += se_config->output_w * 83562306a36Sopenharmony_ci (se_config->output_h - 83662306a36Sopenharmony_ci min(se_config->input_h, se_config->output_h)); 83762306a36Sopenharmony_ci denominator = (htotal - 2) * se_config->output_h; 83862306a36Sopenharmony_ci } 83962306a36Sopenharmony_ci 84062306a36Sopenharmony_ci /* mclk can't be slower than pxlclk. */ 84162306a36Sopenharmony_ci if (numerator < denominator) 84262306a36Sopenharmony_ci numerator = denominator = 1; 84362306a36Sopenharmony_ci mclk = (pxlclk * numerator) / denominator; 84462306a36Sopenharmony_ci ret = clk_get_rate(hwdev->mclk); 84562306a36Sopenharmony_ci if (ret < mclk) { 84662306a36Sopenharmony_ci DRM_DEBUG_DRIVER("mclk requirement of %lu kHz can't be met.\n", 84762306a36Sopenharmony_ci mclk / 1000); 84862306a36Sopenharmony_ci return -EINVAL; 84962306a36Sopenharmony_ci } 85062306a36Sopenharmony_ci return ret; 85162306a36Sopenharmony_ci} 85262306a36Sopenharmony_ci 85362306a36Sopenharmony_cistatic int malidp550_enable_memwrite(struct malidp_hw_device *hwdev, 85462306a36Sopenharmony_ci dma_addr_t *addrs, s32 *pitches, 85562306a36Sopenharmony_ci int num_planes, u16 w, u16 h, u32 fmt_id, 85662306a36Sopenharmony_ci const s16 *rgb2yuv_coeffs) 85762306a36Sopenharmony_ci{ 85862306a36Sopenharmony_ci u32 base = MALIDP550_SE_MEMWRITE_BASE; 85962306a36Sopenharmony_ci u32 de_base = malidp_get_block_base(hwdev, MALIDP_DE_BLOCK); 86062306a36Sopenharmony_ci 86162306a36Sopenharmony_ci /* enable the scaling engine block */ 86262306a36Sopenharmony_ci malidp_hw_setbits(hwdev, MALIDP_SCALE_ENGINE_EN, de_base + MALIDP_DE_DISPLAY_FUNC); 86362306a36Sopenharmony_ci 86462306a36Sopenharmony_ci hwdev->mw_state = MW_ONESHOT; 86562306a36Sopenharmony_ci 86662306a36Sopenharmony_ci malidp_hw_write(hwdev, fmt_id, base + MALIDP_MW_FORMAT); 86762306a36Sopenharmony_ci switch (num_planes) { 86862306a36Sopenharmony_ci case 2: 86962306a36Sopenharmony_ci malidp_hw_write(hwdev, lower_32_bits(addrs[1]), base + MALIDP_MW_P2_PTR_LOW); 87062306a36Sopenharmony_ci malidp_hw_write(hwdev, upper_32_bits(addrs[1]), base + MALIDP_MW_P2_PTR_HIGH); 87162306a36Sopenharmony_ci malidp_hw_write(hwdev, pitches[1], base + MALIDP_MW_P2_STRIDE); 87262306a36Sopenharmony_ci fallthrough; 87362306a36Sopenharmony_ci case 1: 87462306a36Sopenharmony_ci malidp_hw_write(hwdev, lower_32_bits(addrs[0]), base + MALIDP_MW_P1_PTR_LOW); 87562306a36Sopenharmony_ci malidp_hw_write(hwdev, upper_32_bits(addrs[0]), base + MALIDP_MW_P1_PTR_HIGH); 87662306a36Sopenharmony_ci malidp_hw_write(hwdev, pitches[0], base + MALIDP_MW_P1_STRIDE); 87762306a36Sopenharmony_ci break; 87862306a36Sopenharmony_ci default: 87962306a36Sopenharmony_ci WARN(1, "Invalid number of planes"); 88062306a36Sopenharmony_ci } 88162306a36Sopenharmony_ci 88262306a36Sopenharmony_ci malidp_hw_write(hwdev, MALIDP_DE_H_ACTIVE(w) | MALIDP_DE_V_ACTIVE(h), 88362306a36Sopenharmony_ci MALIDP550_SE_MEMWRITE_OUT_SIZE); 88462306a36Sopenharmony_ci malidp_hw_setbits(hwdev, MALIDP550_SE_MEMWRITE_ONESHOT | MALIDP_SE_MEMWRITE_EN, 88562306a36Sopenharmony_ci MALIDP550_SE_CONTROL); 88662306a36Sopenharmony_ci 88762306a36Sopenharmony_ci if (rgb2yuv_coeffs) { 88862306a36Sopenharmony_ci int i; 88962306a36Sopenharmony_ci 89062306a36Sopenharmony_ci for (i = 0; i < MALIDP_COLORADJ_NUM_COEFFS; i++) { 89162306a36Sopenharmony_ci malidp_hw_write(hwdev, rgb2yuv_coeffs[i], 89262306a36Sopenharmony_ci MALIDP550_SE_RGB_YUV_COEFFS + i * 4); 89362306a36Sopenharmony_ci } 89462306a36Sopenharmony_ci } 89562306a36Sopenharmony_ci 89662306a36Sopenharmony_ci return 0; 89762306a36Sopenharmony_ci} 89862306a36Sopenharmony_ci 89962306a36Sopenharmony_cistatic void malidp550_disable_memwrite(struct malidp_hw_device *hwdev) 90062306a36Sopenharmony_ci{ 90162306a36Sopenharmony_ci u32 base = malidp_get_block_base(hwdev, MALIDP_DE_BLOCK); 90262306a36Sopenharmony_ci 90362306a36Sopenharmony_ci malidp_hw_clearbits(hwdev, MALIDP550_SE_MEMWRITE_ONESHOT | MALIDP_SE_MEMWRITE_EN, 90462306a36Sopenharmony_ci MALIDP550_SE_CONTROL); 90562306a36Sopenharmony_ci malidp_hw_clearbits(hwdev, MALIDP_SCALE_ENGINE_EN, base + MALIDP_DE_DISPLAY_FUNC); 90662306a36Sopenharmony_ci} 90762306a36Sopenharmony_ci 90862306a36Sopenharmony_cistatic int malidp650_query_hw(struct malidp_hw_device *hwdev) 90962306a36Sopenharmony_ci{ 91062306a36Sopenharmony_ci u32 conf = malidp_hw_read(hwdev, MALIDP550_CONFIG_ID); 91162306a36Sopenharmony_ci u8 ln_size = (conf >> 4) & 0x3, rsize; 91262306a36Sopenharmony_ci 91362306a36Sopenharmony_ci hwdev->min_line_size = 4; 91462306a36Sopenharmony_ci 91562306a36Sopenharmony_ci switch (ln_size) { 91662306a36Sopenharmony_ci case 0: 91762306a36Sopenharmony_ci case 2: 91862306a36Sopenharmony_ci /* reserved values */ 91962306a36Sopenharmony_ci hwdev->max_line_size = 0; 92062306a36Sopenharmony_ci return -EINVAL; 92162306a36Sopenharmony_ci case 1: 92262306a36Sopenharmony_ci hwdev->max_line_size = SZ_4K; 92362306a36Sopenharmony_ci /* two banks of 128KB for rotation memory */ 92462306a36Sopenharmony_ci rsize = 128; 92562306a36Sopenharmony_ci break; 92662306a36Sopenharmony_ci case 3: 92762306a36Sopenharmony_ci hwdev->max_line_size = 2560; 92862306a36Sopenharmony_ci /* two banks of 80KB for rotation memory */ 92962306a36Sopenharmony_ci rsize = 80; 93062306a36Sopenharmony_ci } 93162306a36Sopenharmony_ci 93262306a36Sopenharmony_ci hwdev->rotation_memory[0] = hwdev->rotation_memory[1] = rsize * SZ_1K; 93362306a36Sopenharmony_ci return 0; 93462306a36Sopenharmony_ci} 93562306a36Sopenharmony_ci 93662306a36Sopenharmony_ciconst struct malidp_hw malidp_device[MALIDP_MAX_DEVICES] = { 93762306a36Sopenharmony_ci [MALIDP_500] = { 93862306a36Sopenharmony_ci .map = { 93962306a36Sopenharmony_ci .coeffs_base = MALIDP500_COEFFS_BASE, 94062306a36Sopenharmony_ci .se_base = MALIDP500_SE_BASE, 94162306a36Sopenharmony_ci .dc_base = MALIDP500_DC_BASE, 94262306a36Sopenharmony_ci .out_depth_base = MALIDP500_OUTPUT_DEPTH, 94362306a36Sopenharmony_ci .features = 0, /* no CLEARIRQ register */ 94462306a36Sopenharmony_ci .n_layers = ARRAY_SIZE(malidp500_layers), 94562306a36Sopenharmony_ci .layers = malidp500_layers, 94662306a36Sopenharmony_ci .de_irq_map = { 94762306a36Sopenharmony_ci .irq_mask = MALIDP_DE_IRQ_UNDERRUN | 94862306a36Sopenharmony_ci MALIDP500_DE_IRQ_AXI_ERR | 94962306a36Sopenharmony_ci MALIDP500_DE_IRQ_VSYNC | 95062306a36Sopenharmony_ci MALIDP500_DE_IRQ_GLOBAL, 95162306a36Sopenharmony_ci .vsync_irq = MALIDP500_DE_IRQ_VSYNC, 95262306a36Sopenharmony_ci .err_mask = MALIDP_DE_IRQ_UNDERRUN | 95362306a36Sopenharmony_ci MALIDP500_DE_IRQ_AXI_ERR | 95462306a36Sopenharmony_ci MALIDP500_DE_IRQ_SATURATION, 95562306a36Sopenharmony_ci }, 95662306a36Sopenharmony_ci .se_irq_map = { 95762306a36Sopenharmony_ci .irq_mask = MALIDP500_SE_IRQ_CONF_MODE | 95862306a36Sopenharmony_ci MALIDP500_SE_IRQ_CONF_VALID | 95962306a36Sopenharmony_ci MALIDP500_SE_IRQ_GLOBAL, 96062306a36Sopenharmony_ci .vsync_irq = MALIDP500_SE_IRQ_CONF_VALID, 96162306a36Sopenharmony_ci .err_mask = MALIDP500_SE_IRQ_INIT_BUSY | 96262306a36Sopenharmony_ci MALIDP500_SE_IRQ_AXI_ERROR | 96362306a36Sopenharmony_ci MALIDP500_SE_IRQ_OVERRUN, 96462306a36Sopenharmony_ci }, 96562306a36Sopenharmony_ci .dc_irq_map = { 96662306a36Sopenharmony_ci .irq_mask = MALIDP500_DE_IRQ_CONF_VALID, 96762306a36Sopenharmony_ci .vsync_irq = MALIDP500_DE_IRQ_CONF_VALID, 96862306a36Sopenharmony_ci }, 96962306a36Sopenharmony_ci .pixel_formats = malidp500_de_formats, 97062306a36Sopenharmony_ci .n_pixel_formats = ARRAY_SIZE(malidp500_de_formats), 97162306a36Sopenharmony_ci .bus_align_bytes = 8, 97262306a36Sopenharmony_ci }, 97362306a36Sopenharmony_ci .query_hw = malidp500_query_hw, 97462306a36Sopenharmony_ci .enter_config_mode = malidp500_enter_config_mode, 97562306a36Sopenharmony_ci .leave_config_mode = malidp500_leave_config_mode, 97662306a36Sopenharmony_ci .in_config_mode = malidp500_in_config_mode, 97762306a36Sopenharmony_ci .set_config_valid = malidp500_set_config_valid, 97862306a36Sopenharmony_ci .modeset = malidp500_modeset, 97962306a36Sopenharmony_ci .rotmem_required = malidp500_rotmem_required, 98062306a36Sopenharmony_ci .se_set_scaling_coeffs = malidp500_se_set_scaling_coeffs, 98162306a36Sopenharmony_ci .se_calc_mclk = malidp500_se_calc_mclk, 98262306a36Sopenharmony_ci .enable_memwrite = malidp500_enable_memwrite, 98362306a36Sopenharmony_ci .disable_memwrite = malidp500_disable_memwrite, 98462306a36Sopenharmony_ci .features = MALIDP_DEVICE_LV_HAS_3_STRIDES, 98562306a36Sopenharmony_ci }, 98662306a36Sopenharmony_ci [MALIDP_550] = { 98762306a36Sopenharmony_ci .map = { 98862306a36Sopenharmony_ci .coeffs_base = MALIDP550_COEFFS_BASE, 98962306a36Sopenharmony_ci .se_base = MALIDP550_SE_BASE, 99062306a36Sopenharmony_ci .dc_base = MALIDP550_DC_BASE, 99162306a36Sopenharmony_ci .out_depth_base = MALIDP550_DE_OUTPUT_DEPTH, 99262306a36Sopenharmony_ci .features = MALIDP_REGMAP_HAS_CLEARIRQ | 99362306a36Sopenharmony_ci MALIDP_DEVICE_AFBC_SUPPORT_SPLIT | 99462306a36Sopenharmony_ci MALIDP_DEVICE_AFBC_YUV_420_10_SUPPORT_SPLIT | 99562306a36Sopenharmony_ci MALIDP_DEVICE_AFBC_YUYV_USE_422_P2, 99662306a36Sopenharmony_ci .n_layers = ARRAY_SIZE(malidp550_layers), 99762306a36Sopenharmony_ci .layers = malidp550_layers, 99862306a36Sopenharmony_ci .de_irq_map = { 99962306a36Sopenharmony_ci .irq_mask = MALIDP_DE_IRQ_UNDERRUN | 100062306a36Sopenharmony_ci MALIDP550_DE_IRQ_VSYNC, 100162306a36Sopenharmony_ci .vsync_irq = MALIDP550_DE_IRQ_VSYNC, 100262306a36Sopenharmony_ci .err_mask = MALIDP_DE_IRQ_UNDERRUN | 100362306a36Sopenharmony_ci MALIDP550_DE_IRQ_SATURATION | 100462306a36Sopenharmony_ci MALIDP550_DE_IRQ_AXI_ERR, 100562306a36Sopenharmony_ci }, 100662306a36Sopenharmony_ci .se_irq_map = { 100762306a36Sopenharmony_ci .irq_mask = MALIDP550_SE_IRQ_EOW, 100862306a36Sopenharmony_ci .vsync_irq = MALIDP550_SE_IRQ_EOW, 100962306a36Sopenharmony_ci .err_mask = MALIDP550_SE_IRQ_AXI_ERR | 101062306a36Sopenharmony_ci MALIDP550_SE_IRQ_OVR | 101162306a36Sopenharmony_ci MALIDP550_SE_IRQ_IBSY, 101262306a36Sopenharmony_ci }, 101362306a36Sopenharmony_ci .dc_irq_map = { 101462306a36Sopenharmony_ci .irq_mask = MALIDP550_DC_IRQ_CONF_VALID | 101562306a36Sopenharmony_ci MALIDP550_DC_IRQ_SE, 101662306a36Sopenharmony_ci .vsync_irq = MALIDP550_DC_IRQ_CONF_VALID, 101762306a36Sopenharmony_ci }, 101862306a36Sopenharmony_ci .pixel_formats = malidp550_de_formats, 101962306a36Sopenharmony_ci .n_pixel_formats = ARRAY_SIZE(malidp550_de_formats), 102062306a36Sopenharmony_ci .bus_align_bytes = 8, 102162306a36Sopenharmony_ci }, 102262306a36Sopenharmony_ci .query_hw = malidp550_query_hw, 102362306a36Sopenharmony_ci .enter_config_mode = malidp550_enter_config_mode, 102462306a36Sopenharmony_ci .leave_config_mode = malidp550_leave_config_mode, 102562306a36Sopenharmony_ci .in_config_mode = malidp550_in_config_mode, 102662306a36Sopenharmony_ci .set_config_valid = malidp550_set_config_valid, 102762306a36Sopenharmony_ci .modeset = malidp550_modeset, 102862306a36Sopenharmony_ci .rotmem_required = malidp550_rotmem_required, 102962306a36Sopenharmony_ci .se_set_scaling_coeffs = malidp550_se_set_scaling_coeffs, 103062306a36Sopenharmony_ci .se_calc_mclk = malidp550_se_calc_mclk, 103162306a36Sopenharmony_ci .enable_memwrite = malidp550_enable_memwrite, 103262306a36Sopenharmony_ci .disable_memwrite = malidp550_disable_memwrite, 103362306a36Sopenharmony_ci .features = 0, 103462306a36Sopenharmony_ci }, 103562306a36Sopenharmony_ci [MALIDP_650] = { 103662306a36Sopenharmony_ci .map = { 103762306a36Sopenharmony_ci .coeffs_base = MALIDP550_COEFFS_BASE, 103862306a36Sopenharmony_ci .se_base = MALIDP550_SE_BASE, 103962306a36Sopenharmony_ci .dc_base = MALIDP550_DC_BASE, 104062306a36Sopenharmony_ci .out_depth_base = MALIDP550_DE_OUTPUT_DEPTH, 104162306a36Sopenharmony_ci .features = MALIDP_REGMAP_HAS_CLEARIRQ | 104262306a36Sopenharmony_ci MALIDP_DEVICE_AFBC_SUPPORT_SPLIT | 104362306a36Sopenharmony_ci MALIDP_DEVICE_AFBC_YUYV_USE_422_P2, 104462306a36Sopenharmony_ci .n_layers = ARRAY_SIZE(malidp650_layers), 104562306a36Sopenharmony_ci .layers = malidp650_layers, 104662306a36Sopenharmony_ci .de_irq_map = { 104762306a36Sopenharmony_ci .irq_mask = MALIDP_DE_IRQ_UNDERRUN | 104862306a36Sopenharmony_ci MALIDP650_DE_IRQ_DRIFT | 104962306a36Sopenharmony_ci MALIDP550_DE_IRQ_VSYNC, 105062306a36Sopenharmony_ci .vsync_irq = MALIDP550_DE_IRQ_VSYNC, 105162306a36Sopenharmony_ci .err_mask = MALIDP_DE_IRQ_UNDERRUN | 105262306a36Sopenharmony_ci MALIDP650_DE_IRQ_DRIFT | 105362306a36Sopenharmony_ci MALIDP550_DE_IRQ_SATURATION | 105462306a36Sopenharmony_ci MALIDP550_DE_IRQ_AXI_ERR | 105562306a36Sopenharmony_ci MALIDP650_DE_IRQ_ACEV1 | 105662306a36Sopenharmony_ci MALIDP650_DE_IRQ_ACEV2 | 105762306a36Sopenharmony_ci MALIDP650_DE_IRQ_ACEG | 105862306a36Sopenharmony_ci MALIDP650_DE_IRQ_AXIEP, 105962306a36Sopenharmony_ci }, 106062306a36Sopenharmony_ci .se_irq_map = { 106162306a36Sopenharmony_ci .irq_mask = MALIDP550_SE_IRQ_EOW, 106262306a36Sopenharmony_ci .vsync_irq = MALIDP550_SE_IRQ_EOW, 106362306a36Sopenharmony_ci .err_mask = MALIDP550_SE_IRQ_AXI_ERR | 106462306a36Sopenharmony_ci MALIDP550_SE_IRQ_OVR | 106562306a36Sopenharmony_ci MALIDP550_SE_IRQ_IBSY, 106662306a36Sopenharmony_ci }, 106762306a36Sopenharmony_ci .dc_irq_map = { 106862306a36Sopenharmony_ci .irq_mask = MALIDP550_DC_IRQ_CONF_VALID | 106962306a36Sopenharmony_ci MALIDP550_DC_IRQ_SE, 107062306a36Sopenharmony_ci .vsync_irq = MALIDP550_DC_IRQ_CONF_VALID, 107162306a36Sopenharmony_ci }, 107262306a36Sopenharmony_ci .pixel_formats = malidp650_de_formats, 107362306a36Sopenharmony_ci .n_pixel_formats = ARRAY_SIZE(malidp650_de_formats), 107462306a36Sopenharmony_ci .bus_align_bytes = 16, 107562306a36Sopenharmony_ci }, 107662306a36Sopenharmony_ci .query_hw = malidp650_query_hw, 107762306a36Sopenharmony_ci .enter_config_mode = malidp550_enter_config_mode, 107862306a36Sopenharmony_ci .leave_config_mode = malidp550_leave_config_mode, 107962306a36Sopenharmony_ci .in_config_mode = malidp550_in_config_mode, 108062306a36Sopenharmony_ci .set_config_valid = malidp550_set_config_valid, 108162306a36Sopenharmony_ci .modeset = malidp550_modeset, 108262306a36Sopenharmony_ci .rotmem_required = malidp650_rotmem_required, 108362306a36Sopenharmony_ci .se_set_scaling_coeffs = malidp550_se_set_scaling_coeffs, 108462306a36Sopenharmony_ci .se_calc_mclk = malidp550_se_calc_mclk, 108562306a36Sopenharmony_ci .enable_memwrite = malidp550_enable_memwrite, 108662306a36Sopenharmony_ci .disable_memwrite = malidp550_disable_memwrite, 108762306a36Sopenharmony_ci .features = 0, 108862306a36Sopenharmony_ci }, 108962306a36Sopenharmony_ci}; 109062306a36Sopenharmony_ci 109162306a36Sopenharmony_ciu8 malidp_hw_get_format_id(const struct malidp_hw_regmap *map, 109262306a36Sopenharmony_ci u8 layer_id, u32 format, bool has_modifier) 109362306a36Sopenharmony_ci{ 109462306a36Sopenharmony_ci unsigned int i; 109562306a36Sopenharmony_ci 109662306a36Sopenharmony_ci for (i = 0; i < map->n_pixel_formats; i++) { 109762306a36Sopenharmony_ci if (((map->pixel_formats[i].layer & layer_id) == layer_id) && 109862306a36Sopenharmony_ci (map->pixel_formats[i].format == format)) { 109962306a36Sopenharmony_ci /* 110062306a36Sopenharmony_ci * In some DP550 and DP650, DRM_FORMAT_YUYV + AFBC modifier 110162306a36Sopenharmony_ci * is supported by a different h/w format id than 110262306a36Sopenharmony_ci * DRM_FORMAT_YUYV (only). 110362306a36Sopenharmony_ci */ 110462306a36Sopenharmony_ci if (format == DRM_FORMAT_YUYV && 110562306a36Sopenharmony_ci (has_modifier) && 110662306a36Sopenharmony_ci (map->features & MALIDP_DEVICE_AFBC_YUYV_USE_422_P2)) 110762306a36Sopenharmony_ci return AFBC_YUV_422_FORMAT_ID; 110862306a36Sopenharmony_ci else 110962306a36Sopenharmony_ci return map->pixel_formats[i].id; 111062306a36Sopenharmony_ci } 111162306a36Sopenharmony_ci } 111262306a36Sopenharmony_ci 111362306a36Sopenharmony_ci return MALIDP_INVALID_FORMAT_ID; 111462306a36Sopenharmony_ci} 111562306a36Sopenharmony_ci 111662306a36Sopenharmony_cibool malidp_hw_format_is_linear_only(u32 format) 111762306a36Sopenharmony_ci{ 111862306a36Sopenharmony_ci switch (format) { 111962306a36Sopenharmony_ci case DRM_FORMAT_ARGB2101010: 112062306a36Sopenharmony_ci case DRM_FORMAT_RGBA1010102: 112162306a36Sopenharmony_ci case DRM_FORMAT_BGRA1010102: 112262306a36Sopenharmony_ci case DRM_FORMAT_ARGB8888: 112362306a36Sopenharmony_ci case DRM_FORMAT_RGBA8888: 112462306a36Sopenharmony_ci case DRM_FORMAT_BGRA8888: 112562306a36Sopenharmony_ci case DRM_FORMAT_XBGR8888: 112662306a36Sopenharmony_ci case DRM_FORMAT_XRGB8888: 112762306a36Sopenharmony_ci case DRM_FORMAT_RGBX8888: 112862306a36Sopenharmony_ci case DRM_FORMAT_BGRX8888: 112962306a36Sopenharmony_ci case DRM_FORMAT_RGB888: 113062306a36Sopenharmony_ci case DRM_FORMAT_RGB565: 113162306a36Sopenharmony_ci case DRM_FORMAT_ARGB1555: 113262306a36Sopenharmony_ci case DRM_FORMAT_RGBA5551: 113362306a36Sopenharmony_ci case DRM_FORMAT_BGRA5551: 113462306a36Sopenharmony_ci case DRM_FORMAT_UYVY: 113562306a36Sopenharmony_ci case DRM_FORMAT_XYUV8888: 113662306a36Sopenharmony_ci case DRM_FORMAT_XVYU2101010: 113762306a36Sopenharmony_ci case DRM_FORMAT_X0L2: 113862306a36Sopenharmony_ci case DRM_FORMAT_X0L0: 113962306a36Sopenharmony_ci return true; 114062306a36Sopenharmony_ci default: 114162306a36Sopenharmony_ci return false; 114262306a36Sopenharmony_ci } 114362306a36Sopenharmony_ci} 114462306a36Sopenharmony_ci 114562306a36Sopenharmony_cibool malidp_hw_format_is_afbc_only(u32 format) 114662306a36Sopenharmony_ci{ 114762306a36Sopenharmony_ci switch (format) { 114862306a36Sopenharmony_ci case DRM_FORMAT_VUY888: 114962306a36Sopenharmony_ci case DRM_FORMAT_VUY101010: 115062306a36Sopenharmony_ci case DRM_FORMAT_YUV420_8BIT: 115162306a36Sopenharmony_ci case DRM_FORMAT_YUV420_10BIT: 115262306a36Sopenharmony_ci return true; 115362306a36Sopenharmony_ci default: 115462306a36Sopenharmony_ci return false; 115562306a36Sopenharmony_ci } 115662306a36Sopenharmony_ci} 115762306a36Sopenharmony_ci 115862306a36Sopenharmony_cistatic void malidp_hw_clear_irq(struct malidp_hw_device *hwdev, u8 block, u32 irq) 115962306a36Sopenharmony_ci{ 116062306a36Sopenharmony_ci u32 base = malidp_get_block_base(hwdev, block); 116162306a36Sopenharmony_ci 116262306a36Sopenharmony_ci if (hwdev->hw->map.features & MALIDP_REGMAP_HAS_CLEARIRQ) 116362306a36Sopenharmony_ci malidp_hw_write(hwdev, irq, base + MALIDP_REG_CLEARIRQ); 116462306a36Sopenharmony_ci else 116562306a36Sopenharmony_ci malidp_hw_write(hwdev, irq, base + MALIDP_REG_STATUS); 116662306a36Sopenharmony_ci} 116762306a36Sopenharmony_ci 116862306a36Sopenharmony_cistatic irqreturn_t malidp_de_irq(int irq, void *arg) 116962306a36Sopenharmony_ci{ 117062306a36Sopenharmony_ci struct drm_device *drm = arg; 117162306a36Sopenharmony_ci struct malidp_drm *malidp = drm_to_malidp(drm); 117262306a36Sopenharmony_ci struct malidp_hw_device *hwdev; 117362306a36Sopenharmony_ci struct malidp_hw *hw; 117462306a36Sopenharmony_ci const struct malidp_irq_map *de; 117562306a36Sopenharmony_ci u32 status, mask, dc_status; 117662306a36Sopenharmony_ci irqreturn_t ret = IRQ_NONE; 117762306a36Sopenharmony_ci 117862306a36Sopenharmony_ci hwdev = malidp->dev; 117962306a36Sopenharmony_ci hw = hwdev->hw; 118062306a36Sopenharmony_ci de = &hw->map.de_irq_map; 118162306a36Sopenharmony_ci 118262306a36Sopenharmony_ci /* 118362306a36Sopenharmony_ci * if we are suspended it is likely that we were invoked because 118462306a36Sopenharmony_ci * we share an interrupt line with some other driver, don't try 118562306a36Sopenharmony_ci * to read the hardware registers 118662306a36Sopenharmony_ci */ 118762306a36Sopenharmony_ci if (hwdev->pm_suspended) 118862306a36Sopenharmony_ci return IRQ_NONE; 118962306a36Sopenharmony_ci 119062306a36Sopenharmony_ci /* first handle the config valid IRQ */ 119162306a36Sopenharmony_ci dc_status = malidp_hw_read(hwdev, hw->map.dc_base + MALIDP_REG_STATUS); 119262306a36Sopenharmony_ci if (dc_status & hw->map.dc_irq_map.vsync_irq) { 119362306a36Sopenharmony_ci malidp_hw_clear_irq(hwdev, MALIDP_DC_BLOCK, dc_status); 119462306a36Sopenharmony_ci /* do we have a page flip event? */ 119562306a36Sopenharmony_ci if (malidp->event != NULL) { 119662306a36Sopenharmony_ci spin_lock(&drm->event_lock); 119762306a36Sopenharmony_ci drm_crtc_send_vblank_event(&malidp->crtc, malidp->event); 119862306a36Sopenharmony_ci malidp->event = NULL; 119962306a36Sopenharmony_ci spin_unlock(&drm->event_lock); 120062306a36Sopenharmony_ci } 120162306a36Sopenharmony_ci atomic_set(&malidp->config_valid, MALIDP_CONFIG_VALID_DONE); 120262306a36Sopenharmony_ci ret = IRQ_WAKE_THREAD; 120362306a36Sopenharmony_ci } 120462306a36Sopenharmony_ci 120562306a36Sopenharmony_ci status = malidp_hw_read(hwdev, MALIDP_REG_STATUS); 120662306a36Sopenharmony_ci if (!(status & de->irq_mask)) 120762306a36Sopenharmony_ci return ret; 120862306a36Sopenharmony_ci 120962306a36Sopenharmony_ci mask = malidp_hw_read(hwdev, MALIDP_REG_MASKIRQ); 121062306a36Sopenharmony_ci /* keep the status of the enabled interrupts, plus the error bits */ 121162306a36Sopenharmony_ci status &= (mask | de->err_mask); 121262306a36Sopenharmony_ci if ((status & de->vsync_irq) && malidp->crtc.enabled) 121362306a36Sopenharmony_ci drm_crtc_handle_vblank(&malidp->crtc); 121462306a36Sopenharmony_ci 121562306a36Sopenharmony_ci#ifdef CONFIG_DEBUG_FS 121662306a36Sopenharmony_ci if (status & de->err_mask) { 121762306a36Sopenharmony_ci malidp_error(malidp, &malidp->de_errors, status, 121862306a36Sopenharmony_ci drm_crtc_vblank_count(&malidp->crtc)); 121962306a36Sopenharmony_ci } 122062306a36Sopenharmony_ci#endif 122162306a36Sopenharmony_ci malidp_hw_clear_irq(hwdev, MALIDP_DE_BLOCK, status); 122262306a36Sopenharmony_ci 122362306a36Sopenharmony_ci return (ret == IRQ_NONE) ? IRQ_HANDLED : ret; 122462306a36Sopenharmony_ci} 122562306a36Sopenharmony_ci 122662306a36Sopenharmony_cistatic irqreturn_t malidp_de_irq_thread_handler(int irq, void *arg) 122762306a36Sopenharmony_ci{ 122862306a36Sopenharmony_ci struct drm_device *drm = arg; 122962306a36Sopenharmony_ci struct malidp_drm *malidp = drm_to_malidp(drm); 123062306a36Sopenharmony_ci 123162306a36Sopenharmony_ci wake_up(&malidp->wq); 123262306a36Sopenharmony_ci 123362306a36Sopenharmony_ci return IRQ_HANDLED; 123462306a36Sopenharmony_ci} 123562306a36Sopenharmony_ci 123662306a36Sopenharmony_civoid malidp_de_irq_hw_init(struct malidp_hw_device *hwdev) 123762306a36Sopenharmony_ci{ 123862306a36Sopenharmony_ci /* ensure interrupts are disabled */ 123962306a36Sopenharmony_ci malidp_hw_disable_irq(hwdev, MALIDP_DE_BLOCK, 0xffffffff); 124062306a36Sopenharmony_ci malidp_hw_clear_irq(hwdev, MALIDP_DE_BLOCK, 0xffffffff); 124162306a36Sopenharmony_ci malidp_hw_disable_irq(hwdev, MALIDP_DC_BLOCK, 0xffffffff); 124262306a36Sopenharmony_ci malidp_hw_clear_irq(hwdev, MALIDP_DC_BLOCK, 0xffffffff); 124362306a36Sopenharmony_ci 124462306a36Sopenharmony_ci /* first enable the DC block IRQs */ 124562306a36Sopenharmony_ci malidp_hw_enable_irq(hwdev, MALIDP_DC_BLOCK, 124662306a36Sopenharmony_ci hwdev->hw->map.dc_irq_map.irq_mask); 124762306a36Sopenharmony_ci 124862306a36Sopenharmony_ci /* now enable the DE block IRQs */ 124962306a36Sopenharmony_ci malidp_hw_enable_irq(hwdev, MALIDP_DE_BLOCK, 125062306a36Sopenharmony_ci hwdev->hw->map.de_irq_map.irq_mask); 125162306a36Sopenharmony_ci} 125262306a36Sopenharmony_ci 125362306a36Sopenharmony_ciint malidp_de_irq_init(struct drm_device *drm, int irq) 125462306a36Sopenharmony_ci{ 125562306a36Sopenharmony_ci struct malidp_drm *malidp = drm_to_malidp(drm); 125662306a36Sopenharmony_ci struct malidp_hw_device *hwdev = malidp->dev; 125762306a36Sopenharmony_ci int ret; 125862306a36Sopenharmony_ci 125962306a36Sopenharmony_ci /* ensure interrupts are disabled */ 126062306a36Sopenharmony_ci malidp_hw_disable_irq(hwdev, MALIDP_DE_BLOCK, 0xffffffff); 126162306a36Sopenharmony_ci malidp_hw_clear_irq(hwdev, MALIDP_DE_BLOCK, 0xffffffff); 126262306a36Sopenharmony_ci malidp_hw_disable_irq(hwdev, MALIDP_DC_BLOCK, 0xffffffff); 126362306a36Sopenharmony_ci malidp_hw_clear_irq(hwdev, MALIDP_DC_BLOCK, 0xffffffff); 126462306a36Sopenharmony_ci 126562306a36Sopenharmony_ci ret = devm_request_threaded_irq(drm->dev, irq, malidp_de_irq, 126662306a36Sopenharmony_ci malidp_de_irq_thread_handler, 126762306a36Sopenharmony_ci IRQF_SHARED, "malidp-de", drm); 126862306a36Sopenharmony_ci if (ret < 0) { 126962306a36Sopenharmony_ci DRM_ERROR("failed to install DE IRQ handler\n"); 127062306a36Sopenharmony_ci return ret; 127162306a36Sopenharmony_ci } 127262306a36Sopenharmony_ci 127362306a36Sopenharmony_ci malidp_de_irq_hw_init(hwdev); 127462306a36Sopenharmony_ci 127562306a36Sopenharmony_ci return 0; 127662306a36Sopenharmony_ci} 127762306a36Sopenharmony_ci 127862306a36Sopenharmony_civoid malidp_de_irq_fini(struct malidp_hw_device *hwdev) 127962306a36Sopenharmony_ci{ 128062306a36Sopenharmony_ci malidp_hw_disable_irq(hwdev, MALIDP_DE_BLOCK, 128162306a36Sopenharmony_ci hwdev->hw->map.de_irq_map.irq_mask); 128262306a36Sopenharmony_ci malidp_hw_disable_irq(hwdev, MALIDP_DC_BLOCK, 128362306a36Sopenharmony_ci hwdev->hw->map.dc_irq_map.irq_mask); 128462306a36Sopenharmony_ci} 128562306a36Sopenharmony_ci 128662306a36Sopenharmony_cistatic irqreturn_t malidp_se_irq(int irq, void *arg) 128762306a36Sopenharmony_ci{ 128862306a36Sopenharmony_ci struct drm_device *drm = arg; 128962306a36Sopenharmony_ci struct malidp_drm *malidp = drm_to_malidp(drm); 129062306a36Sopenharmony_ci struct malidp_hw_device *hwdev = malidp->dev; 129162306a36Sopenharmony_ci struct malidp_hw *hw = hwdev->hw; 129262306a36Sopenharmony_ci const struct malidp_irq_map *se = &hw->map.se_irq_map; 129362306a36Sopenharmony_ci u32 status, mask; 129462306a36Sopenharmony_ci 129562306a36Sopenharmony_ci /* 129662306a36Sopenharmony_ci * if we are suspended it is likely that we were invoked because 129762306a36Sopenharmony_ci * we share an interrupt line with some other driver, don't try 129862306a36Sopenharmony_ci * to read the hardware registers 129962306a36Sopenharmony_ci */ 130062306a36Sopenharmony_ci if (hwdev->pm_suspended) 130162306a36Sopenharmony_ci return IRQ_NONE; 130262306a36Sopenharmony_ci 130362306a36Sopenharmony_ci status = malidp_hw_read(hwdev, hw->map.se_base + MALIDP_REG_STATUS); 130462306a36Sopenharmony_ci if (!(status & (se->irq_mask | se->err_mask))) 130562306a36Sopenharmony_ci return IRQ_NONE; 130662306a36Sopenharmony_ci 130762306a36Sopenharmony_ci#ifdef CONFIG_DEBUG_FS 130862306a36Sopenharmony_ci if (status & se->err_mask) 130962306a36Sopenharmony_ci malidp_error(malidp, &malidp->se_errors, status, 131062306a36Sopenharmony_ci drm_crtc_vblank_count(&malidp->crtc)); 131162306a36Sopenharmony_ci#endif 131262306a36Sopenharmony_ci mask = malidp_hw_read(hwdev, hw->map.se_base + MALIDP_REG_MASKIRQ); 131362306a36Sopenharmony_ci status &= mask; 131462306a36Sopenharmony_ci 131562306a36Sopenharmony_ci if (status & se->vsync_irq) { 131662306a36Sopenharmony_ci switch (hwdev->mw_state) { 131762306a36Sopenharmony_ci case MW_ONESHOT: 131862306a36Sopenharmony_ci drm_writeback_signal_completion(&malidp->mw_connector, 0); 131962306a36Sopenharmony_ci break; 132062306a36Sopenharmony_ci case MW_STOP: 132162306a36Sopenharmony_ci drm_writeback_signal_completion(&malidp->mw_connector, 0); 132262306a36Sopenharmony_ci /* disable writeback after stop */ 132362306a36Sopenharmony_ci hwdev->mw_state = MW_NOT_ENABLED; 132462306a36Sopenharmony_ci break; 132562306a36Sopenharmony_ci case MW_RESTART: 132662306a36Sopenharmony_ci drm_writeback_signal_completion(&malidp->mw_connector, 0); 132762306a36Sopenharmony_ci fallthrough; /* to a new start */ 132862306a36Sopenharmony_ci case MW_START: 132962306a36Sopenharmony_ci /* writeback started, need to emulate one-shot mode */ 133062306a36Sopenharmony_ci hw->disable_memwrite(hwdev); 133162306a36Sopenharmony_ci /* 133262306a36Sopenharmony_ci * only set config_valid HW bit if there is no other update 133362306a36Sopenharmony_ci * in progress or if we raced ahead of the DE IRQ handler 133462306a36Sopenharmony_ci * and config_valid flag will not be update until later 133562306a36Sopenharmony_ci */ 133662306a36Sopenharmony_ci status = malidp_hw_read(hwdev, hw->map.dc_base + MALIDP_REG_STATUS); 133762306a36Sopenharmony_ci if ((atomic_read(&malidp->config_valid) != MALIDP_CONFIG_START) || 133862306a36Sopenharmony_ci (status & hw->map.dc_irq_map.vsync_irq)) 133962306a36Sopenharmony_ci hw->set_config_valid(hwdev, 1); 134062306a36Sopenharmony_ci break; 134162306a36Sopenharmony_ci } 134262306a36Sopenharmony_ci } 134362306a36Sopenharmony_ci 134462306a36Sopenharmony_ci malidp_hw_clear_irq(hwdev, MALIDP_SE_BLOCK, status); 134562306a36Sopenharmony_ci 134662306a36Sopenharmony_ci return IRQ_HANDLED; 134762306a36Sopenharmony_ci} 134862306a36Sopenharmony_ci 134962306a36Sopenharmony_civoid malidp_se_irq_hw_init(struct malidp_hw_device *hwdev) 135062306a36Sopenharmony_ci{ 135162306a36Sopenharmony_ci /* ensure interrupts are disabled */ 135262306a36Sopenharmony_ci malidp_hw_disable_irq(hwdev, MALIDP_SE_BLOCK, 0xffffffff); 135362306a36Sopenharmony_ci malidp_hw_clear_irq(hwdev, MALIDP_SE_BLOCK, 0xffffffff); 135462306a36Sopenharmony_ci 135562306a36Sopenharmony_ci malidp_hw_enable_irq(hwdev, MALIDP_SE_BLOCK, 135662306a36Sopenharmony_ci hwdev->hw->map.se_irq_map.irq_mask); 135762306a36Sopenharmony_ci} 135862306a36Sopenharmony_ci 135962306a36Sopenharmony_cistatic irqreturn_t malidp_se_irq_thread_handler(int irq, void *arg) 136062306a36Sopenharmony_ci{ 136162306a36Sopenharmony_ci return IRQ_HANDLED; 136262306a36Sopenharmony_ci} 136362306a36Sopenharmony_ci 136462306a36Sopenharmony_ciint malidp_se_irq_init(struct drm_device *drm, int irq) 136562306a36Sopenharmony_ci{ 136662306a36Sopenharmony_ci struct malidp_drm *malidp = drm_to_malidp(drm); 136762306a36Sopenharmony_ci struct malidp_hw_device *hwdev = malidp->dev; 136862306a36Sopenharmony_ci int ret; 136962306a36Sopenharmony_ci 137062306a36Sopenharmony_ci /* ensure interrupts are disabled */ 137162306a36Sopenharmony_ci malidp_hw_disable_irq(hwdev, MALIDP_SE_BLOCK, 0xffffffff); 137262306a36Sopenharmony_ci malidp_hw_clear_irq(hwdev, MALIDP_SE_BLOCK, 0xffffffff); 137362306a36Sopenharmony_ci 137462306a36Sopenharmony_ci ret = devm_request_threaded_irq(drm->dev, irq, malidp_se_irq, 137562306a36Sopenharmony_ci malidp_se_irq_thread_handler, 137662306a36Sopenharmony_ci IRQF_SHARED, "malidp-se", drm); 137762306a36Sopenharmony_ci if (ret < 0) { 137862306a36Sopenharmony_ci DRM_ERROR("failed to install SE IRQ handler\n"); 137962306a36Sopenharmony_ci return ret; 138062306a36Sopenharmony_ci } 138162306a36Sopenharmony_ci 138262306a36Sopenharmony_ci hwdev->mw_state = MW_NOT_ENABLED; 138362306a36Sopenharmony_ci malidp_se_irq_hw_init(hwdev); 138462306a36Sopenharmony_ci 138562306a36Sopenharmony_ci return 0; 138662306a36Sopenharmony_ci} 138762306a36Sopenharmony_ci 138862306a36Sopenharmony_civoid malidp_se_irq_fini(struct malidp_hw_device *hwdev) 138962306a36Sopenharmony_ci{ 139062306a36Sopenharmony_ci malidp_hw_disable_irq(hwdev, MALIDP_SE_BLOCK, 139162306a36Sopenharmony_ci hwdev->hw->map.se_irq_map.irq_mask); 139262306a36Sopenharmony_ci} 1393