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