162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Copyright 2019 NXP. 462306a36Sopenharmony_ci */ 562306a36Sopenharmony_ci 662306a36Sopenharmony_ci#include <linux/device.h> 762306a36Sopenharmony_ci#include <linux/slab.h> 862306a36Sopenharmony_ci 962306a36Sopenharmony_ci#include "dcss-dev.h" 1062306a36Sopenharmony_ci 1162306a36Sopenharmony_ci#define DCSS_SS_SYS_CTRL 0x00 1262306a36Sopenharmony_ci#define RUN_EN BIT(0) 1362306a36Sopenharmony_ci#define DCSS_SS_DISPLAY 0x10 1462306a36Sopenharmony_ci#define LRC_X_POS 0 1562306a36Sopenharmony_ci#define LRC_X_MASK GENMASK(12, 0) 1662306a36Sopenharmony_ci#define LRC_Y_POS 16 1762306a36Sopenharmony_ci#define LRC_Y_MASK GENMASK(28, 16) 1862306a36Sopenharmony_ci#define DCSS_SS_HSYNC 0x20 1962306a36Sopenharmony_ci#define DCSS_SS_VSYNC 0x30 2062306a36Sopenharmony_ci#define SYNC_START_POS 0 2162306a36Sopenharmony_ci#define SYNC_START_MASK GENMASK(12, 0) 2262306a36Sopenharmony_ci#define SYNC_END_POS 16 2362306a36Sopenharmony_ci#define SYNC_END_MASK GENMASK(28, 16) 2462306a36Sopenharmony_ci#define SYNC_POL BIT(31) 2562306a36Sopenharmony_ci#define DCSS_SS_DE_ULC 0x40 2662306a36Sopenharmony_ci#define ULC_X_POS 0 2762306a36Sopenharmony_ci#define ULC_X_MASK GENMASK(12, 0) 2862306a36Sopenharmony_ci#define ULC_Y_POS 16 2962306a36Sopenharmony_ci#define ULC_Y_MASK GENMASK(28, 16) 3062306a36Sopenharmony_ci#define ULC_POL BIT(31) 3162306a36Sopenharmony_ci#define DCSS_SS_DE_LRC 0x50 3262306a36Sopenharmony_ci#define DCSS_SS_MODE 0x60 3362306a36Sopenharmony_ci#define PIPE_MODE_POS 0 3462306a36Sopenharmony_ci#define PIPE_MODE_MASK GENMASK(1, 0) 3562306a36Sopenharmony_ci#define DCSS_SS_COEFF 0x70 3662306a36Sopenharmony_ci#define HORIZ_A_POS 0 3762306a36Sopenharmony_ci#define HORIZ_A_MASK GENMASK(3, 0) 3862306a36Sopenharmony_ci#define HORIZ_B_POS 4 3962306a36Sopenharmony_ci#define HORIZ_B_MASK GENMASK(7, 4) 4062306a36Sopenharmony_ci#define HORIZ_C_POS 8 4162306a36Sopenharmony_ci#define HORIZ_C_MASK GENMASK(11, 8) 4262306a36Sopenharmony_ci#define HORIZ_H_NORM_POS 12 4362306a36Sopenharmony_ci#define HORIZ_H_NORM_MASK GENMASK(14, 12) 4462306a36Sopenharmony_ci#define VERT_A_POS 16 4562306a36Sopenharmony_ci#define VERT_A_MASK GENMASK(19, 16) 4662306a36Sopenharmony_ci#define VERT_B_POS 20 4762306a36Sopenharmony_ci#define VERT_B_MASK GENMASK(23, 20) 4862306a36Sopenharmony_ci#define VERT_C_POS 24 4962306a36Sopenharmony_ci#define VERT_C_MASK GENMASK(27, 24) 5062306a36Sopenharmony_ci#define VERT_H_NORM_POS 28 5162306a36Sopenharmony_ci#define VERT_H_NORM_MASK GENMASK(30, 28) 5262306a36Sopenharmony_ci#define DCSS_SS_CLIP_CB 0x80 5362306a36Sopenharmony_ci#define DCSS_SS_CLIP_CR 0x90 5462306a36Sopenharmony_ci#define CLIP_MIN_POS 0 5562306a36Sopenharmony_ci#define CLIP_MIN_MASK GENMASK(9, 0) 5662306a36Sopenharmony_ci#define CLIP_MAX_POS 0 5762306a36Sopenharmony_ci#define CLIP_MAX_MASK GENMASK(23, 16) 5862306a36Sopenharmony_ci#define DCSS_SS_INTER_MODE 0xA0 5962306a36Sopenharmony_ci#define INT_EN BIT(0) 6062306a36Sopenharmony_ci#define VSYNC_SHIFT BIT(1) 6162306a36Sopenharmony_ci 6262306a36Sopenharmony_cistruct dcss_ss { 6362306a36Sopenharmony_ci struct device *dev; 6462306a36Sopenharmony_ci void __iomem *base_reg; 6562306a36Sopenharmony_ci u32 base_ofs; 6662306a36Sopenharmony_ci 6762306a36Sopenharmony_ci struct dcss_ctxld *ctxld; 6862306a36Sopenharmony_ci u32 ctx_id; 6962306a36Sopenharmony_ci 7062306a36Sopenharmony_ci bool in_use; 7162306a36Sopenharmony_ci}; 7262306a36Sopenharmony_ci 7362306a36Sopenharmony_cistatic void dcss_ss_write(struct dcss_ss *ss, u32 val, u32 ofs) 7462306a36Sopenharmony_ci{ 7562306a36Sopenharmony_ci if (!ss->in_use) 7662306a36Sopenharmony_ci dcss_writel(val, ss->base_reg + ofs); 7762306a36Sopenharmony_ci 7862306a36Sopenharmony_ci dcss_ctxld_write(ss->ctxld, ss->ctx_id, val, 7962306a36Sopenharmony_ci ss->base_ofs + ofs); 8062306a36Sopenharmony_ci} 8162306a36Sopenharmony_ci 8262306a36Sopenharmony_ciint dcss_ss_init(struct dcss_dev *dcss, unsigned long ss_base) 8362306a36Sopenharmony_ci{ 8462306a36Sopenharmony_ci struct dcss_ss *ss; 8562306a36Sopenharmony_ci 8662306a36Sopenharmony_ci ss = kzalloc(sizeof(*ss), GFP_KERNEL); 8762306a36Sopenharmony_ci if (!ss) 8862306a36Sopenharmony_ci return -ENOMEM; 8962306a36Sopenharmony_ci 9062306a36Sopenharmony_ci dcss->ss = ss; 9162306a36Sopenharmony_ci ss->dev = dcss->dev; 9262306a36Sopenharmony_ci ss->ctxld = dcss->ctxld; 9362306a36Sopenharmony_ci 9462306a36Sopenharmony_ci ss->base_reg = ioremap(ss_base, SZ_4K); 9562306a36Sopenharmony_ci if (!ss->base_reg) { 9662306a36Sopenharmony_ci dev_err(dcss->dev, "ss: unable to remap ss base\n"); 9762306a36Sopenharmony_ci kfree(ss); 9862306a36Sopenharmony_ci return -ENOMEM; 9962306a36Sopenharmony_ci } 10062306a36Sopenharmony_ci 10162306a36Sopenharmony_ci ss->base_ofs = ss_base; 10262306a36Sopenharmony_ci ss->ctx_id = CTX_SB_HP; 10362306a36Sopenharmony_ci 10462306a36Sopenharmony_ci return 0; 10562306a36Sopenharmony_ci} 10662306a36Sopenharmony_ci 10762306a36Sopenharmony_civoid dcss_ss_exit(struct dcss_ss *ss) 10862306a36Sopenharmony_ci{ 10962306a36Sopenharmony_ci /* stop SS */ 11062306a36Sopenharmony_ci dcss_writel(0, ss->base_reg + DCSS_SS_SYS_CTRL); 11162306a36Sopenharmony_ci 11262306a36Sopenharmony_ci if (ss->base_reg) 11362306a36Sopenharmony_ci iounmap(ss->base_reg); 11462306a36Sopenharmony_ci 11562306a36Sopenharmony_ci kfree(ss); 11662306a36Sopenharmony_ci} 11762306a36Sopenharmony_ci 11862306a36Sopenharmony_civoid dcss_ss_subsam_set(struct dcss_ss *ss) 11962306a36Sopenharmony_ci{ 12062306a36Sopenharmony_ci dcss_ss_write(ss, 0x41614161, DCSS_SS_COEFF); 12162306a36Sopenharmony_ci dcss_ss_write(ss, 0, DCSS_SS_MODE); 12262306a36Sopenharmony_ci dcss_ss_write(ss, 0x03ff0000, DCSS_SS_CLIP_CB); 12362306a36Sopenharmony_ci dcss_ss_write(ss, 0x03ff0000, DCSS_SS_CLIP_CR); 12462306a36Sopenharmony_ci} 12562306a36Sopenharmony_ci 12662306a36Sopenharmony_civoid dcss_ss_sync_set(struct dcss_ss *ss, struct videomode *vm, 12762306a36Sopenharmony_ci bool phsync, bool pvsync) 12862306a36Sopenharmony_ci{ 12962306a36Sopenharmony_ci u16 lrc_x, lrc_y; 13062306a36Sopenharmony_ci u16 hsync_start, hsync_end; 13162306a36Sopenharmony_ci u16 vsync_start, vsync_end; 13262306a36Sopenharmony_ci u16 de_ulc_x, de_ulc_y; 13362306a36Sopenharmony_ci u16 de_lrc_x, de_lrc_y; 13462306a36Sopenharmony_ci 13562306a36Sopenharmony_ci lrc_x = vm->hfront_porch + vm->hback_porch + vm->hsync_len + 13662306a36Sopenharmony_ci vm->hactive - 1; 13762306a36Sopenharmony_ci lrc_y = vm->vfront_porch + vm->vback_porch + vm->vsync_len + 13862306a36Sopenharmony_ci vm->vactive - 1; 13962306a36Sopenharmony_ci 14062306a36Sopenharmony_ci dcss_ss_write(ss, (lrc_y << LRC_Y_POS) | lrc_x, DCSS_SS_DISPLAY); 14162306a36Sopenharmony_ci 14262306a36Sopenharmony_ci hsync_start = vm->hfront_porch + vm->hback_porch + vm->hsync_len + 14362306a36Sopenharmony_ci vm->hactive - 1; 14462306a36Sopenharmony_ci hsync_end = vm->hsync_len - 1; 14562306a36Sopenharmony_ci 14662306a36Sopenharmony_ci dcss_ss_write(ss, (phsync ? SYNC_POL : 0) | 14762306a36Sopenharmony_ci ((u32)hsync_end << SYNC_END_POS) | hsync_start, 14862306a36Sopenharmony_ci DCSS_SS_HSYNC); 14962306a36Sopenharmony_ci 15062306a36Sopenharmony_ci vsync_start = vm->vfront_porch - 1; 15162306a36Sopenharmony_ci vsync_end = vm->vfront_porch + vm->vsync_len - 1; 15262306a36Sopenharmony_ci 15362306a36Sopenharmony_ci dcss_ss_write(ss, (pvsync ? SYNC_POL : 0) | 15462306a36Sopenharmony_ci ((u32)vsync_end << SYNC_END_POS) | vsync_start, 15562306a36Sopenharmony_ci DCSS_SS_VSYNC); 15662306a36Sopenharmony_ci 15762306a36Sopenharmony_ci de_ulc_x = vm->hsync_len + vm->hback_porch - 1; 15862306a36Sopenharmony_ci de_ulc_y = vm->vsync_len + vm->vfront_porch + vm->vback_porch; 15962306a36Sopenharmony_ci 16062306a36Sopenharmony_ci dcss_ss_write(ss, SYNC_POL | ((u32)de_ulc_y << ULC_Y_POS) | de_ulc_x, 16162306a36Sopenharmony_ci DCSS_SS_DE_ULC); 16262306a36Sopenharmony_ci 16362306a36Sopenharmony_ci de_lrc_x = vm->hsync_len + vm->hback_porch + vm->hactive - 1; 16462306a36Sopenharmony_ci de_lrc_y = vm->vsync_len + vm->vfront_porch + vm->vback_porch + 16562306a36Sopenharmony_ci vm->vactive - 1; 16662306a36Sopenharmony_ci 16762306a36Sopenharmony_ci dcss_ss_write(ss, (de_lrc_y << LRC_Y_POS) | de_lrc_x, DCSS_SS_DE_LRC); 16862306a36Sopenharmony_ci} 16962306a36Sopenharmony_ci 17062306a36Sopenharmony_civoid dcss_ss_enable(struct dcss_ss *ss) 17162306a36Sopenharmony_ci{ 17262306a36Sopenharmony_ci dcss_ss_write(ss, RUN_EN, DCSS_SS_SYS_CTRL); 17362306a36Sopenharmony_ci ss->in_use = true; 17462306a36Sopenharmony_ci} 17562306a36Sopenharmony_ci 17662306a36Sopenharmony_civoid dcss_ss_shutoff(struct dcss_ss *ss) 17762306a36Sopenharmony_ci{ 17862306a36Sopenharmony_ci dcss_writel(0, ss->base_reg + DCSS_SS_SYS_CTRL); 17962306a36Sopenharmony_ci ss->in_use = false; 18062306a36Sopenharmony_ci} 181