18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Copyright (C) 2017 Samsung Electronics Co.Ltd 48c2ecf20Sopenharmony_ci * Author: 58c2ecf20Sopenharmony_ci * Andrzej Pietrasiewicz <andrzejtp2010@gmail.com> 68c2ecf20Sopenharmony_ci */ 78c2ecf20Sopenharmony_ci 88c2ecf20Sopenharmony_ci#include <linux/clk.h> 98c2ecf20Sopenharmony_ci#include <linux/component.h> 108c2ecf20Sopenharmony_ci#include <linux/err.h> 118c2ecf20Sopenharmony_ci#include <linux/interrupt.h> 128c2ecf20Sopenharmony_ci#include <linux/io.h> 138c2ecf20Sopenharmony_ci#include <linux/kernel.h> 148c2ecf20Sopenharmony_ci#include <linux/of_device.h> 158c2ecf20Sopenharmony_ci#include <linux/platform_device.h> 168c2ecf20Sopenharmony_ci#include <linux/pm_runtime.h> 178c2ecf20Sopenharmony_ci 188c2ecf20Sopenharmony_ci#include <drm/drm_fourcc.h> 198c2ecf20Sopenharmony_ci#include <drm/exynos_drm.h> 208c2ecf20Sopenharmony_ci 218c2ecf20Sopenharmony_ci#include "exynos_drm_drv.h" 228c2ecf20Sopenharmony_ci#include "exynos_drm_fb.h" 238c2ecf20Sopenharmony_ci#include "exynos_drm_ipp.h" 248c2ecf20Sopenharmony_ci#include "regs-scaler.h" 258c2ecf20Sopenharmony_ci 268c2ecf20Sopenharmony_ci#define scaler_read(offset) readl(scaler->regs + (offset)) 278c2ecf20Sopenharmony_ci#define scaler_write(cfg, offset) writel(cfg, scaler->regs + (offset)) 288c2ecf20Sopenharmony_ci#define SCALER_MAX_CLK 4 298c2ecf20Sopenharmony_ci#define SCALER_AUTOSUSPEND_DELAY 2000 308c2ecf20Sopenharmony_ci#define SCALER_RESET_WAIT_RETRIES 100 318c2ecf20Sopenharmony_ci 328c2ecf20Sopenharmony_cistruct scaler_data { 338c2ecf20Sopenharmony_ci const char *clk_name[SCALER_MAX_CLK]; 348c2ecf20Sopenharmony_ci unsigned int num_clk; 358c2ecf20Sopenharmony_ci const struct exynos_drm_ipp_formats *formats; 368c2ecf20Sopenharmony_ci unsigned int num_formats; 378c2ecf20Sopenharmony_ci}; 388c2ecf20Sopenharmony_ci 398c2ecf20Sopenharmony_cistruct scaler_context { 408c2ecf20Sopenharmony_ci struct exynos_drm_ipp ipp; 418c2ecf20Sopenharmony_ci struct drm_device *drm_dev; 428c2ecf20Sopenharmony_ci void *dma_priv; 438c2ecf20Sopenharmony_ci struct device *dev; 448c2ecf20Sopenharmony_ci void __iomem *regs; 458c2ecf20Sopenharmony_ci struct clk *clock[SCALER_MAX_CLK]; 468c2ecf20Sopenharmony_ci struct exynos_drm_ipp_task *task; 478c2ecf20Sopenharmony_ci const struct scaler_data *scaler_data; 488c2ecf20Sopenharmony_ci}; 498c2ecf20Sopenharmony_ci 508c2ecf20Sopenharmony_cistruct scaler_format { 518c2ecf20Sopenharmony_ci u32 drm_fmt; 528c2ecf20Sopenharmony_ci u32 internal_fmt; 538c2ecf20Sopenharmony_ci u32 chroma_tile_w; 548c2ecf20Sopenharmony_ci u32 chroma_tile_h; 558c2ecf20Sopenharmony_ci}; 568c2ecf20Sopenharmony_ci 578c2ecf20Sopenharmony_cistatic const struct scaler_format scaler_formats[] = { 588c2ecf20Sopenharmony_ci { DRM_FORMAT_NV12, SCALER_YUV420_2P_UV, 8, 8 }, 598c2ecf20Sopenharmony_ci { DRM_FORMAT_NV21, SCALER_YUV420_2P_VU, 8, 8 }, 608c2ecf20Sopenharmony_ci { DRM_FORMAT_YUV420, SCALER_YUV420_3P, 8, 8 }, 618c2ecf20Sopenharmony_ci { DRM_FORMAT_YUYV, SCALER_YUV422_1P_YUYV, 16, 16 }, 628c2ecf20Sopenharmony_ci { DRM_FORMAT_UYVY, SCALER_YUV422_1P_UYVY, 16, 16 }, 638c2ecf20Sopenharmony_ci { DRM_FORMAT_YVYU, SCALER_YUV422_1P_YVYU, 16, 16 }, 648c2ecf20Sopenharmony_ci { DRM_FORMAT_NV16, SCALER_YUV422_2P_UV, 8, 16 }, 658c2ecf20Sopenharmony_ci { DRM_FORMAT_NV61, SCALER_YUV422_2P_VU, 8, 16 }, 668c2ecf20Sopenharmony_ci { DRM_FORMAT_YUV422, SCALER_YUV422_3P, 8, 16 }, 678c2ecf20Sopenharmony_ci { DRM_FORMAT_NV24, SCALER_YUV444_2P_UV, 16, 16 }, 688c2ecf20Sopenharmony_ci { DRM_FORMAT_NV42, SCALER_YUV444_2P_VU, 16, 16 }, 698c2ecf20Sopenharmony_ci { DRM_FORMAT_YUV444, SCALER_YUV444_3P, 16, 16 }, 708c2ecf20Sopenharmony_ci { DRM_FORMAT_RGB565, SCALER_RGB_565, 0, 0 }, 718c2ecf20Sopenharmony_ci { DRM_FORMAT_XRGB1555, SCALER_ARGB1555, 0, 0 }, 728c2ecf20Sopenharmony_ci { DRM_FORMAT_ARGB1555, SCALER_ARGB1555, 0, 0 }, 738c2ecf20Sopenharmony_ci { DRM_FORMAT_XRGB4444, SCALER_ARGB4444, 0, 0 }, 748c2ecf20Sopenharmony_ci { DRM_FORMAT_ARGB4444, SCALER_ARGB4444, 0, 0 }, 758c2ecf20Sopenharmony_ci { DRM_FORMAT_XRGB8888, SCALER_ARGB8888, 0, 0 }, 768c2ecf20Sopenharmony_ci { DRM_FORMAT_ARGB8888, SCALER_ARGB8888, 0, 0 }, 778c2ecf20Sopenharmony_ci { DRM_FORMAT_RGBX8888, SCALER_RGBA8888, 0, 0 }, 788c2ecf20Sopenharmony_ci { DRM_FORMAT_RGBA8888, SCALER_RGBA8888, 0, 0 }, 798c2ecf20Sopenharmony_ci}; 808c2ecf20Sopenharmony_ci 818c2ecf20Sopenharmony_cistatic const struct scaler_format *scaler_get_format(u32 drm_fmt) 828c2ecf20Sopenharmony_ci{ 838c2ecf20Sopenharmony_ci int i; 848c2ecf20Sopenharmony_ci 858c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(scaler_formats); i++) 868c2ecf20Sopenharmony_ci if (scaler_formats[i].drm_fmt == drm_fmt) 878c2ecf20Sopenharmony_ci return &scaler_formats[i]; 888c2ecf20Sopenharmony_ci 898c2ecf20Sopenharmony_ci return NULL; 908c2ecf20Sopenharmony_ci} 918c2ecf20Sopenharmony_ci 928c2ecf20Sopenharmony_cistatic inline int scaler_reset(struct scaler_context *scaler) 938c2ecf20Sopenharmony_ci{ 948c2ecf20Sopenharmony_ci int retry = SCALER_RESET_WAIT_RETRIES; 958c2ecf20Sopenharmony_ci 968c2ecf20Sopenharmony_ci scaler_write(SCALER_CFG_SOFT_RESET, SCALER_CFG); 978c2ecf20Sopenharmony_ci do { 988c2ecf20Sopenharmony_ci cpu_relax(); 998c2ecf20Sopenharmony_ci } while (--retry > 1 && 1008c2ecf20Sopenharmony_ci scaler_read(SCALER_CFG) & SCALER_CFG_SOFT_RESET); 1018c2ecf20Sopenharmony_ci do { 1028c2ecf20Sopenharmony_ci cpu_relax(); 1038c2ecf20Sopenharmony_ci scaler_write(1, SCALER_INT_EN); 1048c2ecf20Sopenharmony_ci } while (--retry > 0 && scaler_read(SCALER_INT_EN) != 1); 1058c2ecf20Sopenharmony_ci 1068c2ecf20Sopenharmony_ci return retry ? 0 : -EIO; 1078c2ecf20Sopenharmony_ci} 1088c2ecf20Sopenharmony_ci 1098c2ecf20Sopenharmony_cistatic inline void scaler_enable_int(struct scaler_context *scaler) 1108c2ecf20Sopenharmony_ci{ 1118c2ecf20Sopenharmony_ci u32 val; 1128c2ecf20Sopenharmony_ci 1138c2ecf20Sopenharmony_ci val = SCALER_INT_EN_TIMEOUT | 1148c2ecf20Sopenharmony_ci SCALER_INT_EN_ILLEGAL_BLEND | 1158c2ecf20Sopenharmony_ci SCALER_INT_EN_ILLEGAL_RATIO | 1168c2ecf20Sopenharmony_ci SCALER_INT_EN_ILLEGAL_DST_HEIGHT | 1178c2ecf20Sopenharmony_ci SCALER_INT_EN_ILLEGAL_DST_WIDTH | 1188c2ecf20Sopenharmony_ci SCALER_INT_EN_ILLEGAL_DST_V_POS | 1198c2ecf20Sopenharmony_ci SCALER_INT_EN_ILLEGAL_DST_H_POS | 1208c2ecf20Sopenharmony_ci SCALER_INT_EN_ILLEGAL_DST_C_SPAN | 1218c2ecf20Sopenharmony_ci SCALER_INT_EN_ILLEGAL_DST_Y_SPAN | 1228c2ecf20Sopenharmony_ci SCALER_INT_EN_ILLEGAL_DST_CR_BASE | 1238c2ecf20Sopenharmony_ci SCALER_INT_EN_ILLEGAL_DST_CB_BASE | 1248c2ecf20Sopenharmony_ci SCALER_INT_EN_ILLEGAL_DST_Y_BASE | 1258c2ecf20Sopenharmony_ci SCALER_INT_EN_ILLEGAL_DST_COLOR | 1268c2ecf20Sopenharmony_ci SCALER_INT_EN_ILLEGAL_SRC_HEIGHT | 1278c2ecf20Sopenharmony_ci SCALER_INT_EN_ILLEGAL_SRC_WIDTH | 1288c2ecf20Sopenharmony_ci SCALER_INT_EN_ILLEGAL_SRC_CV_POS | 1298c2ecf20Sopenharmony_ci SCALER_INT_EN_ILLEGAL_SRC_CH_POS | 1308c2ecf20Sopenharmony_ci SCALER_INT_EN_ILLEGAL_SRC_YV_POS | 1318c2ecf20Sopenharmony_ci SCALER_INT_EN_ILLEGAL_SRC_YH_POS | 1328c2ecf20Sopenharmony_ci SCALER_INT_EN_ILLEGAL_DST_SPAN | 1338c2ecf20Sopenharmony_ci SCALER_INT_EN_ILLEGAL_SRC_Y_SPAN | 1348c2ecf20Sopenharmony_ci SCALER_INT_EN_ILLEGAL_SRC_CR_BASE | 1358c2ecf20Sopenharmony_ci SCALER_INT_EN_ILLEGAL_SRC_CB_BASE | 1368c2ecf20Sopenharmony_ci SCALER_INT_EN_ILLEGAL_SRC_Y_BASE | 1378c2ecf20Sopenharmony_ci SCALER_INT_EN_ILLEGAL_SRC_COLOR | 1388c2ecf20Sopenharmony_ci SCALER_INT_EN_FRAME_END; 1398c2ecf20Sopenharmony_ci scaler_write(val, SCALER_INT_EN); 1408c2ecf20Sopenharmony_ci} 1418c2ecf20Sopenharmony_ci 1428c2ecf20Sopenharmony_cistatic inline void scaler_set_src_fmt(struct scaler_context *scaler, 1438c2ecf20Sopenharmony_ci u32 src_fmt, u32 tile) 1448c2ecf20Sopenharmony_ci{ 1458c2ecf20Sopenharmony_ci u32 val; 1468c2ecf20Sopenharmony_ci 1478c2ecf20Sopenharmony_ci val = SCALER_SRC_CFG_SET_COLOR_FORMAT(src_fmt) | (tile << 10); 1488c2ecf20Sopenharmony_ci scaler_write(val, SCALER_SRC_CFG); 1498c2ecf20Sopenharmony_ci} 1508c2ecf20Sopenharmony_ci 1518c2ecf20Sopenharmony_cistatic inline void scaler_set_src_base(struct scaler_context *scaler, 1528c2ecf20Sopenharmony_ci struct exynos_drm_ipp_buffer *src_buf) 1538c2ecf20Sopenharmony_ci{ 1548c2ecf20Sopenharmony_ci static unsigned int bases[] = { 1558c2ecf20Sopenharmony_ci SCALER_SRC_Y_BASE, 1568c2ecf20Sopenharmony_ci SCALER_SRC_CB_BASE, 1578c2ecf20Sopenharmony_ci SCALER_SRC_CR_BASE, 1588c2ecf20Sopenharmony_ci }; 1598c2ecf20Sopenharmony_ci int i; 1608c2ecf20Sopenharmony_ci 1618c2ecf20Sopenharmony_ci for (i = 0; i < src_buf->format->num_planes; ++i) 1628c2ecf20Sopenharmony_ci scaler_write(src_buf->dma_addr[i], bases[i]); 1638c2ecf20Sopenharmony_ci} 1648c2ecf20Sopenharmony_ci 1658c2ecf20Sopenharmony_cistatic inline void scaler_set_src_span(struct scaler_context *scaler, 1668c2ecf20Sopenharmony_ci struct exynos_drm_ipp_buffer *src_buf) 1678c2ecf20Sopenharmony_ci{ 1688c2ecf20Sopenharmony_ci u32 val; 1698c2ecf20Sopenharmony_ci 1708c2ecf20Sopenharmony_ci val = SCALER_SRC_SPAN_SET_Y_SPAN(src_buf->buf.pitch[0] / 1718c2ecf20Sopenharmony_ci src_buf->format->cpp[0]); 1728c2ecf20Sopenharmony_ci 1738c2ecf20Sopenharmony_ci if (src_buf->format->num_planes > 1) 1748c2ecf20Sopenharmony_ci val |= SCALER_SRC_SPAN_SET_C_SPAN(src_buf->buf.pitch[1]); 1758c2ecf20Sopenharmony_ci 1768c2ecf20Sopenharmony_ci scaler_write(val, SCALER_SRC_SPAN); 1778c2ecf20Sopenharmony_ci} 1788c2ecf20Sopenharmony_ci 1798c2ecf20Sopenharmony_cistatic inline void scaler_set_src_luma_chroma_pos(struct scaler_context *scaler, 1808c2ecf20Sopenharmony_ci struct drm_exynos_ipp_task_rect *src_pos, 1818c2ecf20Sopenharmony_ci const struct scaler_format *fmt) 1828c2ecf20Sopenharmony_ci{ 1838c2ecf20Sopenharmony_ci u32 val; 1848c2ecf20Sopenharmony_ci 1858c2ecf20Sopenharmony_ci val = SCALER_SRC_Y_POS_SET_YH_POS(src_pos->x << 2); 1868c2ecf20Sopenharmony_ci val |= SCALER_SRC_Y_POS_SET_YV_POS(src_pos->y << 2); 1878c2ecf20Sopenharmony_ci scaler_write(val, SCALER_SRC_Y_POS); 1888c2ecf20Sopenharmony_ci val = SCALER_SRC_C_POS_SET_CH_POS( 1898c2ecf20Sopenharmony_ci (src_pos->x * fmt->chroma_tile_w / 16) << 2); 1908c2ecf20Sopenharmony_ci val |= SCALER_SRC_C_POS_SET_CV_POS( 1918c2ecf20Sopenharmony_ci (src_pos->y * fmt->chroma_tile_h / 16) << 2); 1928c2ecf20Sopenharmony_ci scaler_write(val, SCALER_SRC_C_POS); 1938c2ecf20Sopenharmony_ci} 1948c2ecf20Sopenharmony_ci 1958c2ecf20Sopenharmony_cistatic inline void scaler_set_src_wh(struct scaler_context *scaler, 1968c2ecf20Sopenharmony_ci struct drm_exynos_ipp_task_rect *src_pos) 1978c2ecf20Sopenharmony_ci{ 1988c2ecf20Sopenharmony_ci u32 val; 1998c2ecf20Sopenharmony_ci 2008c2ecf20Sopenharmony_ci val = SCALER_SRC_WH_SET_WIDTH(src_pos->w); 2018c2ecf20Sopenharmony_ci val |= SCALER_SRC_WH_SET_HEIGHT(src_pos->h); 2028c2ecf20Sopenharmony_ci scaler_write(val, SCALER_SRC_WH); 2038c2ecf20Sopenharmony_ci} 2048c2ecf20Sopenharmony_ci 2058c2ecf20Sopenharmony_cistatic inline void scaler_set_dst_fmt(struct scaler_context *scaler, 2068c2ecf20Sopenharmony_ci u32 dst_fmt) 2078c2ecf20Sopenharmony_ci{ 2088c2ecf20Sopenharmony_ci u32 val; 2098c2ecf20Sopenharmony_ci 2108c2ecf20Sopenharmony_ci val = SCALER_DST_CFG_SET_COLOR_FORMAT(dst_fmt); 2118c2ecf20Sopenharmony_ci scaler_write(val, SCALER_DST_CFG); 2128c2ecf20Sopenharmony_ci} 2138c2ecf20Sopenharmony_ci 2148c2ecf20Sopenharmony_cistatic inline void scaler_set_dst_base(struct scaler_context *scaler, 2158c2ecf20Sopenharmony_ci struct exynos_drm_ipp_buffer *dst_buf) 2168c2ecf20Sopenharmony_ci{ 2178c2ecf20Sopenharmony_ci static unsigned int bases[] = { 2188c2ecf20Sopenharmony_ci SCALER_DST_Y_BASE, 2198c2ecf20Sopenharmony_ci SCALER_DST_CB_BASE, 2208c2ecf20Sopenharmony_ci SCALER_DST_CR_BASE, 2218c2ecf20Sopenharmony_ci }; 2228c2ecf20Sopenharmony_ci int i; 2238c2ecf20Sopenharmony_ci 2248c2ecf20Sopenharmony_ci for (i = 0; i < dst_buf->format->num_planes; ++i) 2258c2ecf20Sopenharmony_ci scaler_write(dst_buf->dma_addr[i], bases[i]); 2268c2ecf20Sopenharmony_ci} 2278c2ecf20Sopenharmony_ci 2288c2ecf20Sopenharmony_cistatic inline void scaler_set_dst_span(struct scaler_context *scaler, 2298c2ecf20Sopenharmony_ci struct exynos_drm_ipp_buffer *dst_buf) 2308c2ecf20Sopenharmony_ci{ 2318c2ecf20Sopenharmony_ci u32 val; 2328c2ecf20Sopenharmony_ci 2338c2ecf20Sopenharmony_ci val = SCALER_DST_SPAN_SET_Y_SPAN(dst_buf->buf.pitch[0] / 2348c2ecf20Sopenharmony_ci dst_buf->format->cpp[0]); 2358c2ecf20Sopenharmony_ci 2368c2ecf20Sopenharmony_ci if (dst_buf->format->num_planes > 1) 2378c2ecf20Sopenharmony_ci val |= SCALER_DST_SPAN_SET_C_SPAN(dst_buf->buf.pitch[1]); 2388c2ecf20Sopenharmony_ci 2398c2ecf20Sopenharmony_ci scaler_write(val, SCALER_DST_SPAN); 2408c2ecf20Sopenharmony_ci} 2418c2ecf20Sopenharmony_ci 2428c2ecf20Sopenharmony_cistatic inline void scaler_set_dst_luma_pos(struct scaler_context *scaler, 2438c2ecf20Sopenharmony_ci struct drm_exynos_ipp_task_rect *dst_pos) 2448c2ecf20Sopenharmony_ci{ 2458c2ecf20Sopenharmony_ci u32 val; 2468c2ecf20Sopenharmony_ci 2478c2ecf20Sopenharmony_ci val = SCALER_DST_WH_SET_WIDTH(dst_pos->w); 2488c2ecf20Sopenharmony_ci val |= SCALER_DST_WH_SET_HEIGHT(dst_pos->h); 2498c2ecf20Sopenharmony_ci scaler_write(val, SCALER_DST_WH); 2508c2ecf20Sopenharmony_ci} 2518c2ecf20Sopenharmony_ci 2528c2ecf20Sopenharmony_cistatic inline void scaler_set_dst_wh(struct scaler_context *scaler, 2538c2ecf20Sopenharmony_ci struct drm_exynos_ipp_task_rect *dst_pos) 2548c2ecf20Sopenharmony_ci{ 2558c2ecf20Sopenharmony_ci u32 val; 2568c2ecf20Sopenharmony_ci 2578c2ecf20Sopenharmony_ci val = SCALER_DST_POS_SET_H_POS(dst_pos->x); 2588c2ecf20Sopenharmony_ci val |= SCALER_DST_POS_SET_V_POS(dst_pos->y); 2598c2ecf20Sopenharmony_ci scaler_write(val, SCALER_DST_POS); 2608c2ecf20Sopenharmony_ci} 2618c2ecf20Sopenharmony_ci 2628c2ecf20Sopenharmony_cistatic inline void scaler_set_hv_ratio(struct scaler_context *scaler, 2638c2ecf20Sopenharmony_ci unsigned int rotation, 2648c2ecf20Sopenharmony_ci struct drm_exynos_ipp_task_rect *src_pos, 2658c2ecf20Sopenharmony_ci struct drm_exynos_ipp_task_rect *dst_pos) 2668c2ecf20Sopenharmony_ci{ 2678c2ecf20Sopenharmony_ci u32 val, h_ratio, v_ratio; 2688c2ecf20Sopenharmony_ci 2698c2ecf20Sopenharmony_ci if (drm_rotation_90_or_270(rotation)) { 2708c2ecf20Sopenharmony_ci h_ratio = (src_pos->h << 16) / dst_pos->w; 2718c2ecf20Sopenharmony_ci v_ratio = (src_pos->w << 16) / dst_pos->h; 2728c2ecf20Sopenharmony_ci } else { 2738c2ecf20Sopenharmony_ci h_ratio = (src_pos->w << 16) / dst_pos->w; 2748c2ecf20Sopenharmony_ci v_ratio = (src_pos->h << 16) / dst_pos->h; 2758c2ecf20Sopenharmony_ci } 2768c2ecf20Sopenharmony_ci 2778c2ecf20Sopenharmony_ci val = SCALER_H_RATIO_SET(h_ratio); 2788c2ecf20Sopenharmony_ci scaler_write(val, SCALER_H_RATIO); 2798c2ecf20Sopenharmony_ci 2808c2ecf20Sopenharmony_ci val = SCALER_V_RATIO_SET(v_ratio); 2818c2ecf20Sopenharmony_ci scaler_write(val, SCALER_V_RATIO); 2828c2ecf20Sopenharmony_ci} 2838c2ecf20Sopenharmony_ci 2848c2ecf20Sopenharmony_cistatic inline void scaler_set_rotation(struct scaler_context *scaler, 2858c2ecf20Sopenharmony_ci unsigned int rotation) 2868c2ecf20Sopenharmony_ci{ 2878c2ecf20Sopenharmony_ci u32 val = 0; 2888c2ecf20Sopenharmony_ci 2898c2ecf20Sopenharmony_ci if (rotation & DRM_MODE_ROTATE_90) 2908c2ecf20Sopenharmony_ci val |= SCALER_ROT_CFG_SET_ROTMODE(SCALER_ROT_MODE_90); 2918c2ecf20Sopenharmony_ci else if (rotation & DRM_MODE_ROTATE_180) 2928c2ecf20Sopenharmony_ci val |= SCALER_ROT_CFG_SET_ROTMODE(SCALER_ROT_MODE_180); 2938c2ecf20Sopenharmony_ci else if (rotation & DRM_MODE_ROTATE_270) 2948c2ecf20Sopenharmony_ci val |= SCALER_ROT_CFG_SET_ROTMODE(SCALER_ROT_MODE_270); 2958c2ecf20Sopenharmony_ci if (rotation & DRM_MODE_REFLECT_X) 2968c2ecf20Sopenharmony_ci val |= SCALER_ROT_CFG_FLIP_X_EN; 2978c2ecf20Sopenharmony_ci if (rotation & DRM_MODE_REFLECT_Y) 2988c2ecf20Sopenharmony_ci val |= SCALER_ROT_CFG_FLIP_Y_EN; 2998c2ecf20Sopenharmony_ci scaler_write(val, SCALER_ROT_CFG); 3008c2ecf20Sopenharmony_ci} 3018c2ecf20Sopenharmony_ci 3028c2ecf20Sopenharmony_cistatic inline void scaler_set_csc(struct scaler_context *scaler, 3038c2ecf20Sopenharmony_ci const struct drm_format_info *fmt) 3048c2ecf20Sopenharmony_ci{ 3058c2ecf20Sopenharmony_ci static const u32 csc_mtx[2][3][3] = { 3068c2ecf20Sopenharmony_ci { /* YCbCr to RGB */ 3078c2ecf20Sopenharmony_ci {0x254, 0x000, 0x331}, 3088c2ecf20Sopenharmony_ci {0x254, 0xf38, 0xe60}, 3098c2ecf20Sopenharmony_ci {0x254, 0x409, 0x000}, 3108c2ecf20Sopenharmony_ci }, 3118c2ecf20Sopenharmony_ci { /* RGB to YCbCr */ 3128c2ecf20Sopenharmony_ci {0x084, 0x102, 0x032}, 3138c2ecf20Sopenharmony_ci {0xfb4, 0xf6b, 0x0e1}, 3148c2ecf20Sopenharmony_ci {0x0e1, 0xf44, 0xfdc}, 3158c2ecf20Sopenharmony_ci }, 3168c2ecf20Sopenharmony_ci }; 3178c2ecf20Sopenharmony_ci int i, j, dir; 3188c2ecf20Sopenharmony_ci 3198c2ecf20Sopenharmony_ci switch (fmt->format) { 3208c2ecf20Sopenharmony_ci case DRM_FORMAT_RGB565: 3218c2ecf20Sopenharmony_ci case DRM_FORMAT_XRGB1555: 3228c2ecf20Sopenharmony_ci case DRM_FORMAT_ARGB1555: 3238c2ecf20Sopenharmony_ci case DRM_FORMAT_XRGB4444: 3248c2ecf20Sopenharmony_ci case DRM_FORMAT_ARGB4444: 3258c2ecf20Sopenharmony_ci case DRM_FORMAT_XRGB8888: 3268c2ecf20Sopenharmony_ci case DRM_FORMAT_ARGB8888: 3278c2ecf20Sopenharmony_ci case DRM_FORMAT_RGBX8888: 3288c2ecf20Sopenharmony_ci case DRM_FORMAT_RGBA8888: 3298c2ecf20Sopenharmony_ci dir = 1; 3308c2ecf20Sopenharmony_ci break; 3318c2ecf20Sopenharmony_ci default: 3328c2ecf20Sopenharmony_ci dir = 0; 3338c2ecf20Sopenharmony_ci } 3348c2ecf20Sopenharmony_ci 3358c2ecf20Sopenharmony_ci for (i = 0; i < 3; i++) 3368c2ecf20Sopenharmony_ci for (j = 0; j < 3; j++) 3378c2ecf20Sopenharmony_ci scaler_write(csc_mtx[dir][i][j], SCALER_CSC_COEF(j, i)); 3388c2ecf20Sopenharmony_ci} 3398c2ecf20Sopenharmony_ci 3408c2ecf20Sopenharmony_cistatic inline void scaler_set_timer(struct scaler_context *scaler, 3418c2ecf20Sopenharmony_ci unsigned int timer, unsigned int divider) 3428c2ecf20Sopenharmony_ci{ 3438c2ecf20Sopenharmony_ci u32 val; 3448c2ecf20Sopenharmony_ci 3458c2ecf20Sopenharmony_ci val = SCALER_TIMEOUT_CTRL_TIMER_ENABLE; 3468c2ecf20Sopenharmony_ci val |= SCALER_TIMEOUT_CTRL_SET_TIMER_VALUE(timer); 3478c2ecf20Sopenharmony_ci val |= SCALER_TIMEOUT_CTRL_SET_TIMER_DIV(divider); 3488c2ecf20Sopenharmony_ci scaler_write(val, SCALER_TIMEOUT_CTRL); 3498c2ecf20Sopenharmony_ci} 3508c2ecf20Sopenharmony_ci 3518c2ecf20Sopenharmony_cistatic inline void scaler_start_hw(struct scaler_context *scaler) 3528c2ecf20Sopenharmony_ci{ 3538c2ecf20Sopenharmony_ci scaler_write(SCALER_CFG_START_CMD, SCALER_CFG); 3548c2ecf20Sopenharmony_ci} 3558c2ecf20Sopenharmony_ci 3568c2ecf20Sopenharmony_cistatic int scaler_commit(struct exynos_drm_ipp *ipp, 3578c2ecf20Sopenharmony_ci struct exynos_drm_ipp_task *task) 3588c2ecf20Sopenharmony_ci{ 3598c2ecf20Sopenharmony_ci struct scaler_context *scaler = 3608c2ecf20Sopenharmony_ci container_of(ipp, struct scaler_context, ipp); 3618c2ecf20Sopenharmony_ci 3628c2ecf20Sopenharmony_ci struct drm_exynos_ipp_task_rect *src_pos = &task->src.rect; 3638c2ecf20Sopenharmony_ci struct drm_exynos_ipp_task_rect *dst_pos = &task->dst.rect; 3648c2ecf20Sopenharmony_ci const struct scaler_format *src_fmt, *dst_fmt; 3658c2ecf20Sopenharmony_ci 3668c2ecf20Sopenharmony_ci src_fmt = scaler_get_format(task->src.buf.fourcc); 3678c2ecf20Sopenharmony_ci dst_fmt = scaler_get_format(task->dst.buf.fourcc); 3688c2ecf20Sopenharmony_ci 3698c2ecf20Sopenharmony_ci pm_runtime_get_sync(scaler->dev); 3708c2ecf20Sopenharmony_ci if (scaler_reset(scaler)) { 3718c2ecf20Sopenharmony_ci pm_runtime_put(scaler->dev); 3728c2ecf20Sopenharmony_ci return -EIO; 3738c2ecf20Sopenharmony_ci } 3748c2ecf20Sopenharmony_ci 3758c2ecf20Sopenharmony_ci scaler->task = task; 3768c2ecf20Sopenharmony_ci 3778c2ecf20Sopenharmony_ci scaler_set_src_fmt( 3788c2ecf20Sopenharmony_ci scaler, src_fmt->internal_fmt, task->src.buf.modifier != 0); 3798c2ecf20Sopenharmony_ci scaler_set_src_base(scaler, &task->src); 3808c2ecf20Sopenharmony_ci scaler_set_src_span(scaler, &task->src); 3818c2ecf20Sopenharmony_ci scaler_set_src_luma_chroma_pos(scaler, src_pos, src_fmt); 3828c2ecf20Sopenharmony_ci scaler_set_src_wh(scaler, src_pos); 3838c2ecf20Sopenharmony_ci 3848c2ecf20Sopenharmony_ci scaler_set_dst_fmt(scaler, dst_fmt->internal_fmt); 3858c2ecf20Sopenharmony_ci scaler_set_dst_base(scaler, &task->dst); 3868c2ecf20Sopenharmony_ci scaler_set_dst_span(scaler, &task->dst); 3878c2ecf20Sopenharmony_ci scaler_set_dst_luma_pos(scaler, dst_pos); 3888c2ecf20Sopenharmony_ci scaler_set_dst_wh(scaler, dst_pos); 3898c2ecf20Sopenharmony_ci 3908c2ecf20Sopenharmony_ci scaler_set_hv_ratio(scaler, task->transform.rotation, src_pos, dst_pos); 3918c2ecf20Sopenharmony_ci scaler_set_rotation(scaler, task->transform.rotation); 3928c2ecf20Sopenharmony_ci 3938c2ecf20Sopenharmony_ci scaler_set_csc(scaler, task->src.format); 3948c2ecf20Sopenharmony_ci 3958c2ecf20Sopenharmony_ci scaler_set_timer(scaler, 0xffff, 0xf); 3968c2ecf20Sopenharmony_ci 3978c2ecf20Sopenharmony_ci scaler_enable_int(scaler); 3988c2ecf20Sopenharmony_ci scaler_start_hw(scaler); 3998c2ecf20Sopenharmony_ci 4008c2ecf20Sopenharmony_ci return 0; 4018c2ecf20Sopenharmony_ci} 4028c2ecf20Sopenharmony_ci 4038c2ecf20Sopenharmony_cistatic struct exynos_drm_ipp_funcs ipp_funcs = { 4048c2ecf20Sopenharmony_ci .commit = scaler_commit, 4058c2ecf20Sopenharmony_ci}; 4068c2ecf20Sopenharmony_ci 4078c2ecf20Sopenharmony_cistatic inline void scaler_disable_int(struct scaler_context *scaler) 4088c2ecf20Sopenharmony_ci{ 4098c2ecf20Sopenharmony_ci scaler_write(0, SCALER_INT_EN); 4108c2ecf20Sopenharmony_ci} 4118c2ecf20Sopenharmony_ci 4128c2ecf20Sopenharmony_cistatic inline u32 scaler_get_int_status(struct scaler_context *scaler) 4138c2ecf20Sopenharmony_ci{ 4148c2ecf20Sopenharmony_ci u32 val = scaler_read(SCALER_INT_STATUS); 4158c2ecf20Sopenharmony_ci 4168c2ecf20Sopenharmony_ci scaler_write(val, SCALER_INT_STATUS); 4178c2ecf20Sopenharmony_ci 4188c2ecf20Sopenharmony_ci return val; 4198c2ecf20Sopenharmony_ci} 4208c2ecf20Sopenharmony_ci 4218c2ecf20Sopenharmony_cistatic inline int scaler_task_done(u32 val) 4228c2ecf20Sopenharmony_ci{ 4238c2ecf20Sopenharmony_ci return val & SCALER_INT_STATUS_FRAME_END ? 0 : -EINVAL; 4248c2ecf20Sopenharmony_ci} 4258c2ecf20Sopenharmony_ci 4268c2ecf20Sopenharmony_cistatic irqreturn_t scaler_irq_handler(int irq, void *arg) 4278c2ecf20Sopenharmony_ci{ 4288c2ecf20Sopenharmony_ci struct scaler_context *scaler = arg; 4298c2ecf20Sopenharmony_ci 4308c2ecf20Sopenharmony_ci u32 val = scaler_get_int_status(scaler); 4318c2ecf20Sopenharmony_ci 4328c2ecf20Sopenharmony_ci scaler_disable_int(scaler); 4338c2ecf20Sopenharmony_ci 4348c2ecf20Sopenharmony_ci if (scaler->task) { 4358c2ecf20Sopenharmony_ci struct exynos_drm_ipp_task *task = scaler->task; 4368c2ecf20Sopenharmony_ci 4378c2ecf20Sopenharmony_ci scaler->task = NULL; 4388c2ecf20Sopenharmony_ci pm_runtime_mark_last_busy(scaler->dev); 4398c2ecf20Sopenharmony_ci pm_runtime_put_autosuspend(scaler->dev); 4408c2ecf20Sopenharmony_ci exynos_drm_ipp_task_done(task, scaler_task_done(val)); 4418c2ecf20Sopenharmony_ci } 4428c2ecf20Sopenharmony_ci 4438c2ecf20Sopenharmony_ci return IRQ_HANDLED; 4448c2ecf20Sopenharmony_ci} 4458c2ecf20Sopenharmony_ci 4468c2ecf20Sopenharmony_cistatic int scaler_bind(struct device *dev, struct device *master, void *data) 4478c2ecf20Sopenharmony_ci{ 4488c2ecf20Sopenharmony_ci struct scaler_context *scaler = dev_get_drvdata(dev); 4498c2ecf20Sopenharmony_ci struct drm_device *drm_dev = data; 4508c2ecf20Sopenharmony_ci struct exynos_drm_ipp *ipp = &scaler->ipp; 4518c2ecf20Sopenharmony_ci 4528c2ecf20Sopenharmony_ci scaler->drm_dev = drm_dev; 4538c2ecf20Sopenharmony_ci ipp->drm_dev = drm_dev; 4548c2ecf20Sopenharmony_ci exynos_drm_register_dma(drm_dev, dev, &scaler->dma_priv); 4558c2ecf20Sopenharmony_ci 4568c2ecf20Sopenharmony_ci exynos_drm_ipp_register(dev, ipp, &ipp_funcs, 4578c2ecf20Sopenharmony_ci DRM_EXYNOS_IPP_CAP_CROP | DRM_EXYNOS_IPP_CAP_ROTATE | 4588c2ecf20Sopenharmony_ci DRM_EXYNOS_IPP_CAP_SCALE | DRM_EXYNOS_IPP_CAP_CONVERT, 4598c2ecf20Sopenharmony_ci scaler->scaler_data->formats, 4608c2ecf20Sopenharmony_ci scaler->scaler_data->num_formats, "scaler"); 4618c2ecf20Sopenharmony_ci 4628c2ecf20Sopenharmony_ci dev_info(dev, "The exynos scaler has been probed successfully\n"); 4638c2ecf20Sopenharmony_ci 4648c2ecf20Sopenharmony_ci return 0; 4658c2ecf20Sopenharmony_ci} 4668c2ecf20Sopenharmony_ci 4678c2ecf20Sopenharmony_cistatic void scaler_unbind(struct device *dev, struct device *master, 4688c2ecf20Sopenharmony_ci void *data) 4698c2ecf20Sopenharmony_ci{ 4708c2ecf20Sopenharmony_ci struct scaler_context *scaler = dev_get_drvdata(dev); 4718c2ecf20Sopenharmony_ci struct exynos_drm_ipp *ipp = &scaler->ipp; 4728c2ecf20Sopenharmony_ci 4738c2ecf20Sopenharmony_ci exynos_drm_ipp_unregister(dev, ipp); 4748c2ecf20Sopenharmony_ci exynos_drm_unregister_dma(scaler->drm_dev, scaler->dev, 4758c2ecf20Sopenharmony_ci &scaler->dma_priv); 4768c2ecf20Sopenharmony_ci} 4778c2ecf20Sopenharmony_ci 4788c2ecf20Sopenharmony_cistatic const struct component_ops scaler_component_ops = { 4798c2ecf20Sopenharmony_ci .bind = scaler_bind, 4808c2ecf20Sopenharmony_ci .unbind = scaler_unbind, 4818c2ecf20Sopenharmony_ci}; 4828c2ecf20Sopenharmony_ci 4838c2ecf20Sopenharmony_cistatic int scaler_probe(struct platform_device *pdev) 4848c2ecf20Sopenharmony_ci{ 4858c2ecf20Sopenharmony_ci struct device *dev = &pdev->dev; 4868c2ecf20Sopenharmony_ci struct resource *regs_res; 4878c2ecf20Sopenharmony_ci struct scaler_context *scaler; 4888c2ecf20Sopenharmony_ci int irq; 4898c2ecf20Sopenharmony_ci int ret, i; 4908c2ecf20Sopenharmony_ci 4918c2ecf20Sopenharmony_ci scaler = devm_kzalloc(dev, sizeof(*scaler), GFP_KERNEL); 4928c2ecf20Sopenharmony_ci if (!scaler) 4938c2ecf20Sopenharmony_ci return -ENOMEM; 4948c2ecf20Sopenharmony_ci 4958c2ecf20Sopenharmony_ci scaler->scaler_data = 4968c2ecf20Sopenharmony_ci (struct scaler_data *)of_device_get_match_data(dev); 4978c2ecf20Sopenharmony_ci 4988c2ecf20Sopenharmony_ci scaler->dev = dev; 4998c2ecf20Sopenharmony_ci regs_res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 5008c2ecf20Sopenharmony_ci scaler->regs = devm_ioremap_resource(dev, regs_res); 5018c2ecf20Sopenharmony_ci if (IS_ERR(scaler->regs)) 5028c2ecf20Sopenharmony_ci return PTR_ERR(scaler->regs); 5038c2ecf20Sopenharmony_ci 5048c2ecf20Sopenharmony_ci irq = platform_get_irq(pdev, 0); 5058c2ecf20Sopenharmony_ci if (irq < 0) 5068c2ecf20Sopenharmony_ci return irq; 5078c2ecf20Sopenharmony_ci 5088c2ecf20Sopenharmony_ci ret = devm_request_threaded_irq(dev, irq, NULL, scaler_irq_handler, 5098c2ecf20Sopenharmony_ci IRQF_ONESHOT, "drm_scaler", scaler); 5108c2ecf20Sopenharmony_ci if (ret < 0) { 5118c2ecf20Sopenharmony_ci dev_err(dev, "failed to request irq\n"); 5128c2ecf20Sopenharmony_ci return ret; 5138c2ecf20Sopenharmony_ci } 5148c2ecf20Sopenharmony_ci 5158c2ecf20Sopenharmony_ci for (i = 0; i < scaler->scaler_data->num_clk; ++i) { 5168c2ecf20Sopenharmony_ci scaler->clock[i] = devm_clk_get(dev, 5178c2ecf20Sopenharmony_ci scaler->scaler_data->clk_name[i]); 5188c2ecf20Sopenharmony_ci if (IS_ERR(scaler->clock[i])) { 5198c2ecf20Sopenharmony_ci dev_err(dev, "failed to get clock\n"); 5208c2ecf20Sopenharmony_ci return PTR_ERR(scaler->clock[i]); 5218c2ecf20Sopenharmony_ci } 5228c2ecf20Sopenharmony_ci } 5238c2ecf20Sopenharmony_ci 5248c2ecf20Sopenharmony_ci pm_runtime_use_autosuspend(dev); 5258c2ecf20Sopenharmony_ci pm_runtime_set_autosuspend_delay(dev, SCALER_AUTOSUSPEND_DELAY); 5268c2ecf20Sopenharmony_ci pm_runtime_enable(dev); 5278c2ecf20Sopenharmony_ci platform_set_drvdata(pdev, scaler); 5288c2ecf20Sopenharmony_ci 5298c2ecf20Sopenharmony_ci ret = component_add(dev, &scaler_component_ops); 5308c2ecf20Sopenharmony_ci if (ret) 5318c2ecf20Sopenharmony_ci goto err_ippdrv_register; 5328c2ecf20Sopenharmony_ci 5338c2ecf20Sopenharmony_ci return 0; 5348c2ecf20Sopenharmony_ci 5358c2ecf20Sopenharmony_cierr_ippdrv_register: 5368c2ecf20Sopenharmony_ci pm_runtime_dont_use_autosuspend(dev); 5378c2ecf20Sopenharmony_ci pm_runtime_disable(dev); 5388c2ecf20Sopenharmony_ci return ret; 5398c2ecf20Sopenharmony_ci} 5408c2ecf20Sopenharmony_ci 5418c2ecf20Sopenharmony_cistatic int scaler_remove(struct platform_device *pdev) 5428c2ecf20Sopenharmony_ci{ 5438c2ecf20Sopenharmony_ci struct device *dev = &pdev->dev; 5448c2ecf20Sopenharmony_ci 5458c2ecf20Sopenharmony_ci component_del(dev, &scaler_component_ops); 5468c2ecf20Sopenharmony_ci pm_runtime_dont_use_autosuspend(dev); 5478c2ecf20Sopenharmony_ci pm_runtime_disable(dev); 5488c2ecf20Sopenharmony_ci 5498c2ecf20Sopenharmony_ci return 0; 5508c2ecf20Sopenharmony_ci} 5518c2ecf20Sopenharmony_ci 5528c2ecf20Sopenharmony_ci#ifdef CONFIG_PM 5538c2ecf20Sopenharmony_ci 5548c2ecf20Sopenharmony_cistatic int clk_disable_unprepare_wrapper(struct clk *clk) 5558c2ecf20Sopenharmony_ci{ 5568c2ecf20Sopenharmony_ci clk_disable_unprepare(clk); 5578c2ecf20Sopenharmony_ci 5588c2ecf20Sopenharmony_ci return 0; 5598c2ecf20Sopenharmony_ci} 5608c2ecf20Sopenharmony_ci 5618c2ecf20Sopenharmony_cistatic int scaler_clk_ctrl(struct scaler_context *scaler, bool enable) 5628c2ecf20Sopenharmony_ci{ 5638c2ecf20Sopenharmony_ci int (*clk_fun)(struct clk *clk), i; 5648c2ecf20Sopenharmony_ci 5658c2ecf20Sopenharmony_ci clk_fun = enable ? clk_prepare_enable : clk_disable_unprepare_wrapper; 5668c2ecf20Sopenharmony_ci 5678c2ecf20Sopenharmony_ci for (i = 0; i < scaler->scaler_data->num_clk; ++i) 5688c2ecf20Sopenharmony_ci clk_fun(scaler->clock[i]); 5698c2ecf20Sopenharmony_ci 5708c2ecf20Sopenharmony_ci return 0; 5718c2ecf20Sopenharmony_ci} 5728c2ecf20Sopenharmony_ci 5738c2ecf20Sopenharmony_cistatic int scaler_runtime_suspend(struct device *dev) 5748c2ecf20Sopenharmony_ci{ 5758c2ecf20Sopenharmony_ci struct scaler_context *scaler = dev_get_drvdata(dev); 5768c2ecf20Sopenharmony_ci 5778c2ecf20Sopenharmony_ci return scaler_clk_ctrl(scaler, false); 5788c2ecf20Sopenharmony_ci} 5798c2ecf20Sopenharmony_ci 5808c2ecf20Sopenharmony_cistatic int scaler_runtime_resume(struct device *dev) 5818c2ecf20Sopenharmony_ci{ 5828c2ecf20Sopenharmony_ci struct scaler_context *scaler = dev_get_drvdata(dev); 5838c2ecf20Sopenharmony_ci 5848c2ecf20Sopenharmony_ci return scaler_clk_ctrl(scaler, true); 5858c2ecf20Sopenharmony_ci} 5868c2ecf20Sopenharmony_ci#endif 5878c2ecf20Sopenharmony_ci 5888c2ecf20Sopenharmony_cistatic const struct dev_pm_ops scaler_pm_ops = { 5898c2ecf20Sopenharmony_ci SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, 5908c2ecf20Sopenharmony_ci pm_runtime_force_resume) 5918c2ecf20Sopenharmony_ci SET_RUNTIME_PM_OPS(scaler_runtime_suspend, scaler_runtime_resume, NULL) 5928c2ecf20Sopenharmony_ci}; 5938c2ecf20Sopenharmony_ci 5948c2ecf20Sopenharmony_cistatic const struct drm_exynos_ipp_limit scaler_5420_two_pixel_hv_limits[] = { 5958c2ecf20Sopenharmony_ci { IPP_SIZE_LIMIT(BUFFER, .h = { 16, SZ_8K }, .v = { 16, SZ_8K }) }, 5968c2ecf20Sopenharmony_ci { IPP_SIZE_LIMIT(AREA, .h.align = 2, .v.align = 2) }, 5978c2ecf20Sopenharmony_ci { IPP_SCALE_LIMIT(.h = { 65536 * 1 / 4, 65536 * 16 }, 5988c2ecf20Sopenharmony_ci .v = { 65536 * 1 / 4, 65536 * 16 }) }, 5998c2ecf20Sopenharmony_ci}; 6008c2ecf20Sopenharmony_ci 6018c2ecf20Sopenharmony_cistatic const struct drm_exynos_ipp_limit scaler_5420_two_pixel_h_limits[] = { 6028c2ecf20Sopenharmony_ci { IPP_SIZE_LIMIT(BUFFER, .h = { 16, SZ_8K }, .v = { 16, SZ_8K }) }, 6038c2ecf20Sopenharmony_ci { IPP_SIZE_LIMIT(AREA, .h.align = 2, .v.align = 1) }, 6048c2ecf20Sopenharmony_ci { IPP_SCALE_LIMIT(.h = { 65536 * 1 / 4, 65536 * 16 }, 6058c2ecf20Sopenharmony_ci .v = { 65536 * 1 / 4, 65536 * 16 }) }, 6068c2ecf20Sopenharmony_ci}; 6078c2ecf20Sopenharmony_ci 6088c2ecf20Sopenharmony_cistatic const struct drm_exynos_ipp_limit scaler_5420_one_pixel_limits[] = { 6098c2ecf20Sopenharmony_ci { IPP_SIZE_LIMIT(BUFFER, .h = { 16, SZ_8K }, .v = { 16, SZ_8K }) }, 6108c2ecf20Sopenharmony_ci { IPP_SCALE_LIMIT(.h = { 65536 * 1 / 4, 65536 * 16 }, 6118c2ecf20Sopenharmony_ci .v = { 65536 * 1 / 4, 65536 * 16 }) }, 6128c2ecf20Sopenharmony_ci}; 6138c2ecf20Sopenharmony_ci 6148c2ecf20Sopenharmony_cistatic const struct drm_exynos_ipp_limit scaler_5420_tile_limits[] = { 6158c2ecf20Sopenharmony_ci { IPP_SIZE_LIMIT(BUFFER, .h = { 16, SZ_8K }, .v = { 16, SZ_8K })}, 6168c2ecf20Sopenharmony_ci { IPP_SIZE_LIMIT(AREA, .h.align = 16, .v.align = 16) }, 6178c2ecf20Sopenharmony_ci { IPP_SCALE_LIMIT(.h = {1, 1}, .v = {1, 1})}, 6188c2ecf20Sopenharmony_ci { } 6198c2ecf20Sopenharmony_ci}; 6208c2ecf20Sopenharmony_ci 6218c2ecf20Sopenharmony_ci#define IPP_SRCDST_TILE_FORMAT(f, l) \ 6228c2ecf20Sopenharmony_ci IPP_SRCDST_MFORMAT(f, DRM_FORMAT_MOD_SAMSUNG_16_16_TILE, (l)) 6238c2ecf20Sopenharmony_ci 6248c2ecf20Sopenharmony_cistatic const struct exynos_drm_ipp_formats exynos5420_formats[] = { 6258c2ecf20Sopenharmony_ci /* SCALER_YUV420_2P_UV */ 6268c2ecf20Sopenharmony_ci { IPP_SRCDST_FORMAT(NV21, scaler_5420_two_pixel_hv_limits) }, 6278c2ecf20Sopenharmony_ci 6288c2ecf20Sopenharmony_ci /* SCALER_YUV420_2P_VU */ 6298c2ecf20Sopenharmony_ci { IPP_SRCDST_FORMAT(NV12, scaler_5420_two_pixel_hv_limits) }, 6308c2ecf20Sopenharmony_ci 6318c2ecf20Sopenharmony_ci /* SCALER_YUV420_3P */ 6328c2ecf20Sopenharmony_ci { IPP_SRCDST_FORMAT(YUV420, scaler_5420_two_pixel_hv_limits) }, 6338c2ecf20Sopenharmony_ci 6348c2ecf20Sopenharmony_ci /* SCALER_YUV422_1P_YUYV */ 6358c2ecf20Sopenharmony_ci { IPP_SRCDST_FORMAT(YUYV, scaler_5420_two_pixel_h_limits) }, 6368c2ecf20Sopenharmony_ci 6378c2ecf20Sopenharmony_ci /* SCALER_YUV422_1P_UYVY */ 6388c2ecf20Sopenharmony_ci { IPP_SRCDST_FORMAT(UYVY, scaler_5420_two_pixel_h_limits) }, 6398c2ecf20Sopenharmony_ci 6408c2ecf20Sopenharmony_ci /* SCALER_YUV422_1P_YVYU */ 6418c2ecf20Sopenharmony_ci { IPP_SRCDST_FORMAT(YVYU, scaler_5420_two_pixel_h_limits) }, 6428c2ecf20Sopenharmony_ci 6438c2ecf20Sopenharmony_ci /* SCALER_YUV422_2P_UV */ 6448c2ecf20Sopenharmony_ci { IPP_SRCDST_FORMAT(NV61, scaler_5420_two_pixel_h_limits) }, 6458c2ecf20Sopenharmony_ci 6468c2ecf20Sopenharmony_ci /* SCALER_YUV422_2P_VU */ 6478c2ecf20Sopenharmony_ci { IPP_SRCDST_FORMAT(NV16, scaler_5420_two_pixel_h_limits) }, 6488c2ecf20Sopenharmony_ci 6498c2ecf20Sopenharmony_ci /* SCALER_YUV422_3P */ 6508c2ecf20Sopenharmony_ci { IPP_SRCDST_FORMAT(YUV422, scaler_5420_two_pixel_h_limits) }, 6518c2ecf20Sopenharmony_ci 6528c2ecf20Sopenharmony_ci /* SCALER_YUV444_2P_UV */ 6538c2ecf20Sopenharmony_ci { IPP_SRCDST_FORMAT(NV42, scaler_5420_one_pixel_limits) }, 6548c2ecf20Sopenharmony_ci 6558c2ecf20Sopenharmony_ci /* SCALER_YUV444_2P_VU */ 6568c2ecf20Sopenharmony_ci { IPP_SRCDST_FORMAT(NV24, scaler_5420_one_pixel_limits) }, 6578c2ecf20Sopenharmony_ci 6588c2ecf20Sopenharmony_ci /* SCALER_YUV444_3P */ 6598c2ecf20Sopenharmony_ci { IPP_SRCDST_FORMAT(YUV444, scaler_5420_one_pixel_limits) }, 6608c2ecf20Sopenharmony_ci 6618c2ecf20Sopenharmony_ci /* SCALER_RGB_565 */ 6628c2ecf20Sopenharmony_ci { IPP_SRCDST_FORMAT(RGB565, scaler_5420_one_pixel_limits) }, 6638c2ecf20Sopenharmony_ci 6648c2ecf20Sopenharmony_ci /* SCALER_ARGB1555 */ 6658c2ecf20Sopenharmony_ci { IPP_SRCDST_FORMAT(XRGB1555, scaler_5420_one_pixel_limits) }, 6668c2ecf20Sopenharmony_ci 6678c2ecf20Sopenharmony_ci /* SCALER_ARGB1555 */ 6688c2ecf20Sopenharmony_ci { IPP_SRCDST_FORMAT(ARGB1555, scaler_5420_one_pixel_limits) }, 6698c2ecf20Sopenharmony_ci 6708c2ecf20Sopenharmony_ci /* SCALER_ARGB4444 */ 6718c2ecf20Sopenharmony_ci { IPP_SRCDST_FORMAT(XRGB4444, scaler_5420_one_pixel_limits) }, 6728c2ecf20Sopenharmony_ci 6738c2ecf20Sopenharmony_ci /* SCALER_ARGB4444 */ 6748c2ecf20Sopenharmony_ci { IPP_SRCDST_FORMAT(ARGB4444, scaler_5420_one_pixel_limits) }, 6758c2ecf20Sopenharmony_ci 6768c2ecf20Sopenharmony_ci /* SCALER_ARGB8888 */ 6778c2ecf20Sopenharmony_ci { IPP_SRCDST_FORMAT(XRGB8888, scaler_5420_one_pixel_limits) }, 6788c2ecf20Sopenharmony_ci 6798c2ecf20Sopenharmony_ci /* SCALER_ARGB8888 */ 6808c2ecf20Sopenharmony_ci { IPP_SRCDST_FORMAT(ARGB8888, scaler_5420_one_pixel_limits) }, 6818c2ecf20Sopenharmony_ci 6828c2ecf20Sopenharmony_ci /* SCALER_RGBA8888 */ 6838c2ecf20Sopenharmony_ci { IPP_SRCDST_FORMAT(RGBX8888, scaler_5420_one_pixel_limits) }, 6848c2ecf20Sopenharmony_ci 6858c2ecf20Sopenharmony_ci /* SCALER_RGBA8888 */ 6868c2ecf20Sopenharmony_ci { IPP_SRCDST_FORMAT(RGBA8888, scaler_5420_one_pixel_limits) }, 6878c2ecf20Sopenharmony_ci 6888c2ecf20Sopenharmony_ci /* SCALER_YUV420_2P_UV TILE */ 6898c2ecf20Sopenharmony_ci { IPP_SRCDST_TILE_FORMAT(NV21, scaler_5420_tile_limits) }, 6908c2ecf20Sopenharmony_ci 6918c2ecf20Sopenharmony_ci /* SCALER_YUV420_2P_VU TILE */ 6928c2ecf20Sopenharmony_ci { IPP_SRCDST_TILE_FORMAT(NV12, scaler_5420_tile_limits) }, 6938c2ecf20Sopenharmony_ci 6948c2ecf20Sopenharmony_ci /* SCALER_YUV420_3P TILE */ 6958c2ecf20Sopenharmony_ci { IPP_SRCDST_TILE_FORMAT(YUV420, scaler_5420_tile_limits) }, 6968c2ecf20Sopenharmony_ci 6978c2ecf20Sopenharmony_ci /* SCALER_YUV422_1P_YUYV TILE */ 6988c2ecf20Sopenharmony_ci { IPP_SRCDST_TILE_FORMAT(YUYV, scaler_5420_tile_limits) }, 6998c2ecf20Sopenharmony_ci}; 7008c2ecf20Sopenharmony_ci 7018c2ecf20Sopenharmony_cistatic const struct scaler_data exynos5420_data = { 7028c2ecf20Sopenharmony_ci .clk_name = {"mscl"}, 7038c2ecf20Sopenharmony_ci .num_clk = 1, 7048c2ecf20Sopenharmony_ci .formats = exynos5420_formats, 7058c2ecf20Sopenharmony_ci .num_formats = ARRAY_SIZE(exynos5420_formats), 7068c2ecf20Sopenharmony_ci}; 7078c2ecf20Sopenharmony_ci 7088c2ecf20Sopenharmony_cistatic const struct scaler_data exynos5433_data = { 7098c2ecf20Sopenharmony_ci .clk_name = {"pclk", "aclk", "aclk_xiu"}, 7108c2ecf20Sopenharmony_ci .num_clk = 3, 7118c2ecf20Sopenharmony_ci .formats = exynos5420_formats, /* intentional */ 7128c2ecf20Sopenharmony_ci .num_formats = ARRAY_SIZE(exynos5420_formats), 7138c2ecf20Sopenharmony_ci}; 7148c2ecf20Sopenharmony_ci 7158c2ecf20Sopenharmony_cistatic const struct of_device_id exynos_scaler_match[] = { 7168c2ecf20Sopenharmony_ci { 7178c2ecf20Sopenharmony_ci .compatible = "samsung,exynos5420-scaler", 7188c2ecf20Sopenharmony_ci .data = &exynos5420_data, 7198c2ecf20Sopenharmony_ci }, { 7208c2ecf20Sopenharmony_ci .compatible = "samsung,exynos5433-scaler", 7218c2ecf20Sopenharmony_ci .data = &exynos5433_data, 7228c2ecf20Sopenharmony_ci }, { 7238c2ecf20Sopenharmony_ci }, 7248c2ecf20Sopenharmony_ci}; 7258c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(of, exynos_scaler_match); 7268c2ecf20Sopenharmony_ci 7278c2ecf20Sopenharmony_cistruct platform_driver scaler_driver = { 7288c2ecf20Sopenharmony_ci .probe = scaler_probe, 7298c2ecf20Sopenharmony_ci .remove = scaler_remove, 7308c2ecf20Sopenharmony_ci .driver = { 7318c2ecf20Sopenharmony_ci .name = "exynos-scaler", 7328c2ecf20Sopenharmony_ci .owner = THIS_MODULE, 7338c2ecf20Sopenharmony_ci .pm = &scaler_pm_ops, 7348c2ecf20Sopenharmony_ci .of_match_table = exynos_scaler_match, 7358c2ecf20Sopenharmony_ci }, 7368c2ecf20Sopenharmony_ci}; 737