18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Copyright 2019 NXP. 48c2ecf20Sopenharmony_ci */ 58c2ecf20Sopenharmony_ci 68c2ecf20Sopenharmony_ci#include <linux/device.h> 78c2ecf20Sopenharmony_ci#include <linux/slab.h> 88c2ecf20Sopenharmony_ci 98c2ecf20Sopenharmony_ci#include "dcss-dev.h" 108c2ecf20Sopenharmony_ci 118c2ecf20Sopenharmony_ci#define DCSS_SS_SYS_CTRL 0x00 128c2ecf20Sopenharmony_ci#define RUN_EN BIT(0) 138c2ecf20Sopenharmony_ci#define DCSS_SS_DISPLAY 0x10 148c2ecf20Sopenharmony_ci#define LRC_X_POS 0 158c2ecf20Sopenharmony_ci#define LRC_X_MASK GENMASK(12, 0) 168c2ecf20Sopenharmony_ci#define LRC_Y_POS 16 178c2ecf20Sopenharmony_ci#define LRC_Y_MASK GENMASK(28, 16) 188c2ecf20Sopenharmony_ci#define DCSS_SS_HSYNC 0x20 198c2ecf20Sopenharmony_ci#define DCSS_SS_VSYNC 0x30 208c2ecf20Sopenharmony_ci#define SYNC_START_POS 0 218c2ecf20Sopenharmony_ci#define SYNC_START_MASK GENMASK(12, 0) 228c2ecf20Sopenharmony_ci#define SYNC_END_POS 16 238c2ecf20Sopenharmony_ci#define SYNC_END_MASK GENMASK(28, 16) 248c2ecf20Sopenharmony_ci#define SYNC_POL BIT(31) 258c2ecf20Sopenharmony_ci#define DCSS_SS_DE_ULC 0x40 268c2ecf20Sopenharmony_ci#define ULC_X_POS 0 278c2ecf20Sopenharmony_ci#define ULC_X_MASK GENMASK(12, 0) 288c2ecf20Sopenharmony_ci#define ULC_Y_POS 16 298c2ecf20Sopenharmony_ci#define ULC_Y_MASK GENMASK(28, 16) 308c2ecf20Sopenharmony_ci#define ULC_POL BIT(31) 318c2ecf20Sopenharmony_ci#define DCSS_SS_DE_LRC 0x50 328c2ecf20Sopenharmony_ci#define DCSS_SS_MODE 0x60 338c2ecf20Sopenharmony_ci#define PIPE_MODE_POS 0 348c2ecf20Sopenharmony_ci#define PIPE_MODE_MASK GENMASK(1, 0) 358c2ecf20Sopenharmony_ci#define DCSS_SS_COEFF 0x70 368c2ecf20Sopenharmony_ci#define HORIZ_A_POS 0 378c2ecf20Sopenharmony_ci#define HORIZ_A_MASK GENMASK(3, 0) 388c2ecf20Sopenharmony_ci#define HORIZ_B_POS 4 398c2ecf20Sopenharmony_ci#define HORIZ_B_MASK GENMASK(7, 4) 408c2ecf20Sopenharmony_ci#define HORIZ_C_POS 8 418c2ecf20Sopenharmony_ci#define HORIZ_C_MASK GENMASK(11, 8) 428c2ecf20Sopenharmony_ci#define HORIZ_H_NORM_POS 12 438c2ecf20Sopenharmony_ci#define HORIZ_H_NORM_MASK GENMASK(14, 12) 448c2ecf20Sopenharmony_ci#define VERT_A_POS 16 458c2ecf20Sopenharmony_ci#define VERT_A_MASK GENMASK(19, 16) 468c2ecf20Sopenharmony_ci#define VERT_B_POS 20 478c2ecf20Sopenharmony_ci#define VERT_B_MASK GENMASK(23, 20) 488c2ecf20Sopenharmony_ci#define VERT_C_POS 24 498c2ecf20Sopenharmony_ci#define VERT_C_MASK GENMASK(27, 24) 508c2ecf20Sopenharmony_ci#define VERT_H_NORM_POS 28 518c2ecf20Sopenharmony_ci#define VERT_H_NORM_MASK GENMASK(30, 28) 528c2ecf20Sopenharmony_ci#define DCSS_SS_CLIP_CB 0x80 538c2ecf20Sopenharmony_ci#define DCSS_SS_CLIP_CR 0x90 548c2ecf20Sopenharmony_ci#define CLIP_MIN_POS 0 558c2ecf20Sopenharmony_ci#define CLIP_MIN_MASK GENMASK(9, 0) 568c2ecf20Sopenharmony_ci#define CLIP_MAX_POS 0 578c2ecf20Sopenharmony_ci#define CLIP_MAX_MASK GENMASK(23, 16) 588c2ecf20Sopenharmony_ci#define DCSS_SS_INTER_MODE 0xA0 598c2ecf20Sopenharmony_ci#define INT_EN BIT(0) 608c2ecf20Sopenharmony_ci#define VSYNC_SHIFT BIT(1) 618c2ecf20Sopenharmony_ci 628c2ecf20Sopenharmony_cistruct dcss_ss { 638c2ecf20Sopenharmony_ci struct device *dev; 648c2ecf20Sopenharmony_ci void __iomem *base_reg; 658c2ecf20Sopenharmony_ci u32 base_ofs; 668c2ecf20Sopenharmony_ci 678c2ecf20Sopenharmony_ci struct dcss_ctxld *ctxld; 688c2ecf20Sopenharmony_ci u32 ctx_id; 698c2ecf20Sopenharmony_ci 708c2ecf20Sopenharmony_ci bool in_use; 718c2ecf20Sopenharmony_ci}; 728c2ecf20Sopenharmony_ci 738c2ecf20Sopenharmony_cistatic void dcss_ss_write(struct dcss_ss *ss, u32 val, u32 ofs) 748c2ecf20Sopenharmony_ci{ 758c2ecf20Sopenharmony_ci if (!ss->in_use) 768c2ecf20Sopenharmony_ci dcss_writel(val, ss->base_reg + ofs); 778c2ecf20Sopenharmony_ci 788c2ecf20Sopenharmony_ci dcss_ctxld_write(ss->ctxld, ss->ctx_id, val, 798c2ecf20Sopenharmony_ci ss->base_ofs + ofs); 808c2ecf20Sopenharmony_ci} 818c2ecf20Sopenharmony_ci 828c2ecf20Sopenharmony_ciint dcss_ss_init(struct dcss_dev *dcss, unsigned long ss_base) 838c2ecf20Sopenharmony_ci{ 848c2ecf20Sopenharmony_ci struct dcss_ss *ss; 858c2ecf20Sopenharmony_ci 868c2ecf20Sopenharmony_ci ss = kzalloc(sizeof(*ss), GFP_KERNEL); 878c2ecf20Sopenharmony_ci if (!ss) 888c2ecf20Sopenharmony_ci return -ENOMEM; 898c2ecf20Sopenharmony_ci 908c2ecf20Sopenharmony_ci dcss->ss = ss; 918c2ecf20Sopenharmony_ci ss->dev = dcss->dev; 928c2ecf20Sopenharmony_ci ss->ctxld = dcss->ctxld; 938c2ecf20Sopenharmony_ci 948c2ecf20Sopenharmony_ci ss->base_reg = ioremap(ss_base, SZ_4K); 958c2ecf20Sopenharmony_ci if (!ss->base_reg) { 968c2ecf20Sopenharmony_ci dev_err(dcss->dev, "ss: unable to remap ss base\n"); 978c2ecf20Sopenharmony_ci kfree(ss); 988c2ecf20Sopenharmony_ci return -ENOMEM; 998c2ecf20Sopenharmony_ci } 1008c2ecf20Sopenharmony_ci 1018c2ecf20Sopenharmony_ci ss->base_ofs = ss_base; 1028c2ecf20Sopenharmony_ci ss->ctx_id = CTX_SB_HP; 1038c2ecf20Sopenharmony_ci 1048c2ecf20Sopenharmony_ci return 0; 1058c2ecf20Sopenharmony_ci} 1068c2ecf20Sopenharmony_ci 1078c2ecf20Sopenharmony_civoid dcss_ss_exit(struct dcss_ss *ss) 1088c2ecf20Sopenharmony_ci{ 1098c2ecf20Sopenharmony_ci /* stop SS */ 1108c2ecf20Sopenharmony_ci dcss_writel(0, ss->base_reg + DCSS_SS_SYS_CTRL); 1118c2ecf20Sopenharmony_ci 1128c2ecf20Sopenharmony_ci if (ss->base_reg) 1138c2ecf20Sopenharmony_ci iounmap(ss->base_reg); 1148c2ecf20Sopenharmony_ci 1158c2ecf20Sopenharmony_ci kfree(ss); 1168c2ecf20Sopenharmony_ci} 1178c2ecf20Sopenharmony_ci 1188c2ecf20Sopenharmony_civoid dcss_ss_subsam_set(struct dcss_ss *ss) 1198c2ecf20Sopenharmony_ci{ 1208c2ecf20Sopenharmony_ci dcss_ss_write(ss, 0x41614161, DCSS_SS_COEFF); 1218c2ecf20Sopenharmony_ci dcss_ss_write(ss, 0, DCSS_SS_MODE); 1228c2ecf20Sopenharmony_ci dcss_ss_write(ss, 0x03ff0000, DCSS_SS_CLIP_CB); 1238c2ecf20Sopenharmony_ci dcss_ss_write(ss, 0x03ff0000, DCSS_SS_CLIP_CR); 1248c2ecf20Sopenharmony_ci} 1258c2ecf20Sopenharmony_ci 1268c2ecf20Sopenharmony_civoid dcss_ss_sync_set(struct dcss_ss *ss, struct videomode *vm, 1278c2ecf20Sopenharmony_ci bool phsync, bool pvsync) 1288c2ecf20Sopenharmony_ci{ 1298c2ecf20Sopenharmony_ci u16 lrc_x, lrc_y; 1308c2ecf20Sopenharmony_ci u16 hsync_start, hsync_end; 1318c2ecf20Sopenharmony_ci u16 vsync_start, vsync_end; 1328c2ecf20Sopenharmony_ci u16 de_ulc_x, de_ulc_y; 1338c2ecf20Sopenharmony_ci u16 de_lrc_x, de_lrc_y; 1348c2ecf20Sopenharmony_ci 1358c2ecf20Sopenharmony_ci lrc_x = vm->hfront_porch + vm->hback_porch + vm->hsync_len + 1368c2ecf20Sopenharmony_ci vm->hactive - 1; 1378c2ecf20Sopenharmony_ci lrc_y = vm->vfront_porch + vm->vback_porch + vm->vsync_len + 1388c2ecf20Sopenharmony_ci vm->vactive - 1; 1398c2ecf20Sopenharmony_ci 1408c2ecf20Sopenharmony_ci dcss_ss_write(ss, (lrc_y << LRC_Y_POS) | lrc_x, DCSS_SS_DISPLAY); 1418c2ecf20Sopenharmony_ci 1428c2ecf20Sopenharmony_ci hsync_start = vm->hfront_porch + vm->hback_porch + vm->hsync_len + 1438c2ecf20Sopenharmony_ci vm->hactive - 1; 1448c2ecf20Sopenharmony_ci hsync_end = vm->hsync_len - 1; 1458c2ecf20Sopenharmony_ci 1468c2ecf20Sopenharmony_ci dcss_ss_write(ss, (phsync ? SYNC_POL : 0) | 1478c2ecf20Sopenharmony_ci ((u32)hsync_end << SYNC_END_POS) | hsync_start, 1488c2ecf20Sopenharmony_ci DCSS_SS_HSYNC); 1498c2ecf20Sopenharmony_ci 1508c2ecf20Sopenharmony_ci vsync_start = vm->vfront_porch - 1; 1518c2ecf20Sopenharmony_ci vsync_end = vm->vfront_porch + vm->vsync_len - 1; 1528c2ecf20Sopenharmony_ci 1538c2ecf20Sopenharmony_ci dcss_ss_write(ss, (pvsync ? SYNC_POL : 0) | 1548c2ecf20Sopenharmony_ci ((u32)vsync_end << SYNC_END_POS) | vsync_start, 1558c2ecf20Sopenharmony_ci DCSS_SS_VSYNC); 1568c2ecf20Sopenharmony_ci 1578c2ecf20Sopenharmony_ci de_ulc_x = vm->hsync_len + vm->hback_porch - 1; 1588c2ecf20Sopenharmony_ci de_ulc_y = vm->vsync_len + vm->vfront_porch + vm->vback_porch; 1598c2ecf20Sopenharmony_ci 1608c2ecf20Sopenharmony_ci dcss_ss_write(ss, SYNC_POL | ((u32)de_ulc_y << ULC_Y_POS) | de_ulc_x, 1618c2ecf20Sopenharmony_ci DCSS_SS_DE_ULC); 1628c2ecf20Sopenharmony_ci 1638c2ecf20Sopenharmony_ci de_lrc_x = vm->hsync_len + vm->hback_porch + vm->hactive - 1; 1648c2ecf20Sopenharmony_ci de_lrc_y = vm->vsync_len + vm->vfront_porch + vm->vback_porch + 1658c2ecf20Sopenharmony_ci vm->vactive - 1; 1668c2ecf20Sopenharmony_ci 1678c2ecf20Sopenharmony_ci dcss_ss_write(ss, (de_lrc_y << LRC_Y_POS) | de_lrc_x, DCSS_SS_DE_LRC); 1688c2ecf20Sopenharmony_ci} 1698c2ecf20Sopenharmony_ci 1708c2ecf20Sopenharmony_civoid dcss_ss_enable(struct dcss_ss *ss) 1718c2ecf20Sopenharmony_ci{ 1728c2ecf20Sopenharmony_ci dcss_ss_write(ss, RUN_EN, DCSS_SS_SYS_CTRL); 1738c2ecf20Sopenharmony_ci ss->in_use = true; 1748c2ecf20Sopenharmony_ci} 1758c2ecf20Sopenharmony_ci 1768c2ecf20Sopenharmony_civoid dcss_ss_shutoff(struct dcss_ss *ss) 1778c2ecf20Sopenharmony_ci{ 1788c2ecf20Sopenharmony_ci dcss_writel(0, ss->base_reg + DCSS_SS_SYS_CTRL); 1798c2ecf20Sopenharmony_ci ss->in_use = false; 1808c2ecf20Sopenharmony_ci} 181