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