19021c317SLaurentiu Palcu // SPDX-License-Identifier: GPL-2.0
29021c317SLaurentiu Palcu /*
39021c317SLaurentiu Palcu * Copyright 2019 NXP.
49021c317SLaurentiu Palcu */
59021c317SLaurentiu Palcu
69021c317SLaurentiu Palcu #include <linux/device.h>
79021c317SLaurentiu Palcu #include <linux/slab.h>
89021c317SLaurentiu Palcu
99021c317SLaurentiu Palcu #include "dcss-dev.h"
109021c317SLaurentiu Palcu
119021c317SLaurentiu Palcu #define DCSS_SS_SYS_CTRL 0x00
129021c317SLaurentiu Palcu #define RUN_EN BIT(0)
139021c317SLaurentiu Palcu #define DCSS_SS_DISPLAY 0x10
149021c317SLaurentiu Palcu #define LRC_X_POS 0
159021c317SLaurentiu Palcu #define LRC_X_MASK GENMASK(12, 0)
169021c317SLaurentiu Palcu #define LRC_Y_POS 16
179021c317SLaurentiu Palcu #define LRC_Y_MASK GENMASK(28, 16)
189021c317SLaurentiu Palcu #define DCSS_SS_HSYNC 0x20
199021c317SLaurentiu Palcu #define DCSS_SS_VSYNC 0x30
209021c317SLaurentiu Palcu #define SYNC_START_POS 0
219021c317SLaurentiu Palcu #define SYNC_START_MASK GENMASK(12, 0)
229021c317SLaurentiu Palcu #define SYNC_END_POS 16
239021c317SLaurentiu Palcu #define SYNC_END_MASK GENMASK(28, 16)
249021c317SLaurentiu Palcu #define SYNC_POL BIT(31)
259021c317SLaurentiu Palcu #define DCSS_SS_DE_ULC 0x40
269021c317SLaurentiu Palcu #define ULC_X_POS 0
279021c317SLaurentiu Palcu #define ULC_X_MASK GENMASK(12, 0)
289021c317SLaurentiu Palcu #define ULC_Y_POS 16
299021c317SLaurentiu Palcu #define ULC_Y_MASK GENMASK(28, 16)
309021c317SLaurentiu Palcu #define ULC_POL BIT(31)
319021c317SLaurentiu Palcu #define DCSS_SS_DE_LRC 0x50
329021c317SLaurentiu Palcu #define DCSS_SS_MODE 0x60
339021c317SLaurentiu Palcu #define PIPE_MODE_POS 0
349021c317SLaurentiu Palcu #define PIPE_MODE_MASK GENMASK(1, 0)
359021c317SLaurentiu Palcu #define DCSS_SS_COEFF 0x70
369021c317SLaurentiu Palcu #define HORIZ_A_POS 0
379021c317SLaurentiu Palcu #define HORIZ_A_MASK GENMASK(3, 0)
389021c317SLaurentiu Palcu #define HORIZ_B_POS 4
399021c317SLaurentiu Palcu #define HORIZ_B_MASK GENMASK(7, 4)
409021c317SLaurentiu Palcu #define HORIZ_C_POS 8
419021c317SLaurentiu Palcu #define HORIZ_C_MASK GENMASK(11, 8)
429021c317SLaurentiu Palcu #define HORIZ_H_NORM_POS 12
439021c317SLaurentiu Palcu #define HORIZ_H_NORM_MASK GENMASK(14, 12)
449021c317SLaurentiu Palcu #define VERT_A_POS 16
459021c317SLaurentiu Palcu #define VERT_A_MASK GENMASK(19, 16)
469021c317SLaurentiu Palcu #define VERT_B_POS 20
479021c317SLaurentiu Palcu #define VERT_B_MASK GENMASK(23, 20)
489021c317SLaurentiu Palcu #define VERT_C_POS 24
499021c317SLaurentiu Palcu #define VERT_C_MASK GENMASK(27, 24)
509021c317SLaurentiu Palcu #define VERT_H_NORM_POS 28
519021c317SLaurentiu Palcu #define VERT_H_NORM_MASK GENMASK(30, 28)
529021c317SLaurentiu Palcu #define DCSS_SS_CLIP_CB 0x80
539021c317SLaurentiu Palcu #define DCSS_SS_CLIP_CR 0x90
549021c317SLaurentiu Palcu #define CLIP_MIN_POS 0
559021c317SLaurentiu Palcu #define CLIP_MIN_MASK GENMASK(9, 0)
569021c317SLaurentiu Palcu #define CLIP_MAX_POS 0
579021c317SLaurentiu Palcu #define CLIP_MAX_MASK GENMASK(23, 16)
589021c317SLaurentiu Palcu #define DCSS_SS_INTER_MODE 0xA0
599021c317SLaurentiu Palcu #define INT_EN BIT(0)
609021c317SLaurentiu Palcu #define VSYNC_SHIFT BIT(1)
619021c317SLaurentiu Palcu
629021c317SLaurentiu Palcu struct dcss_ss {
639021c317SLaurentiu Palcu struct device *dev;
649021c317SLaurentiu Palcu void __iomem *base_reg;
659021c317SLaurentiu Palcu u32 base_ofs;
669021c317SLaurentiu Palcu
679021c317SLaurentiu Palcu struct dcss_ctxld *ctxld;
689021c317SLaurentiu Palcu u32 ctx_id;
699021c317SLaurentiu Palcu
709021c317SLaurentiu Palcu bool in_use;
719021c317SLaurentiu Palcu };
729021c317SLaurentiu Palcu
dcss_ss_write(struct dcss_ss * ss,u32 val,u32 ofs)739021c317SLaurentiu Palcu static void dcss_ss_write(struct dcss_ss *ss, u32 val, u32 ofs)
749021c317SLaurentiu Palcu {
759021c317SLaurentiu Palcu if (!ss->in_use)
769021c317SLaurentiu Palcu dcss_writel(val, ss->base_reg + ofs);
779021c317SLaurentiu Palcu
789021c317SLaurentiu Palcu dcss_ctxld_write(ss->ctxld, ss->ctx_id, val,
799021c317SLaurentiu Palcu ss->base_ofs + ofs);
809021c317SLaurentiu Palcu }
819021c317SLaurentiu Palcu
dcss_ss_init(struct dcss_dev * dcss,unsigned long ss_base)829021c317SLaurentiu Palcu int dcss_ss_init(struct dcss_dev *dcss, unsigned long ss_base)
839021c317SLaurentiu Palcu {
849021c317SLaurentiu Palcu struct dcss_ss *ss;
859021c317SLaurentiu Palcu
86*2bb98fc1SPhilipp Stanner ss = devm_kzalloc(dcss->dev, sizeof(*ss), GFP_KERNEL);
879021c317SLaurentiu Palcu if (!ss)
889021c317SLaurentiu Palcu return -ENOMEM;
899021c317SLaurentiu Palcu
909021c317SLaurentiu Palcu dcss->ss = ss;
919021c317SLaurentiu Palcu ss->dev = dcss->dev;
929021c317SLaurentiu Palcu ss->ctxld = dcss->ctxld;
939021c317SLaurentiu Palcu
94*2bb98fc1SPhilipp Stanner ss->base_reg = devm_ioremap(ss->dev, ss_base, SZ_4K);
959021c317SLaurentiu Palcu if (!ss->base_reg) {
96*2bb98fc1SPhilipp Stanner dev_err(ss->dev, "ss: unable to remap ss base\n");
979021c317SLaurentiu Palcu return -ENOMEM;
989021c317SLaurentiu Palcu }
999021c317SLaurentiu Palcu
1009021c317SLaurentiu Palcu ss->base_ofs = ss_base;
1019021c317SLaurentiu Palcu ss->ctx_id = CTX_SB_HP;
1029021c317SLaurentiu Palcu
1039021c317SLaurentiu Palcu return 0;
1049021c317SLaurentiu Palcu }
1059021c317SLaurentiu Palcu
dcss_ss_exit(struct dcss_ss * ss)1069021c317SLaurentiu Palcu void dcss_ss_exit(struct dcss_ss *ss)
1079021c317SLaurentiu Palcu {
1089021c317SLaurentiu Palcu /* stop SS */
1099021c317SLaurentiu Palcu dcss_writel(0, ss->base_reg + DCSS_SS_SYS_CTRL);
1109021c317SLaurentiu Palcu }
1119021c317SLaurentiu Palcu
dcss_ss_subsam_set(struct dcss_ss * ss)1129021c317SLaurentiu Palcu void dcss_ss_subsam_set(struct dcss_ss *ss)
1139021c317SLaurentiu Palcu {
1149021c317SLaurentiu Palcu dcss_ss_write(ss, 0x41614161, DCSS_SS_COEFF);
1159021c317SLaurentiu Palcu dcss_ss_write(ss, 0, DCSS_SS_MODE);
1169021c317SLaurentiu Palcu dcss_ss_write(ss, 0x03ff0000, DCSS_SS_CLIP_CB);
1179021c317SLaurentiu Palcu dcss_ss_write(ss, 0x03ff0000, DCSS_SS_CLIP_CR);
1189021c317SLaurentiu Palcu }
1199021c317SLaurentiu Palcu
dcss_ss_sync_set(struct dcss_ss * ss,struct videomode * vm,bool phsync,bool pvsync)1209021c317SLaurentiu Palcu void dcss_ss_sync_set(struct dcss_ss *ss, struct videomode *vm,
1219021c317SLaurentiu Palcu bool phsync, bool pvsync)
1229021c317SLaurentiu Palcu {
1239021c317SLaurentiu Palcu u16 lrc_x, lrc_y;
1249021c317SLaurentiu Palcu u16 hsync_start, hsync_end;
1259021c317SLaurentiu Palcu u16 vsync_start, vsync_end;
1269021c317SLaurentiu Palcu u16 de_ulc_x, de_ulc_y;
1279021c317SLaurentiu Palcu u16 de_lrc_x, de_lrc_y;
1289021c317SLaurentiu Palcu
1299021c317SLaurentiu Palcu lrc_x = vm->hfront_porch + vm->hback_porch + vm->hsync_len +
1309021c317SLaurentiu Palcu vm->hactive - 1;
1319021c317SLaurentiu Palcu lrc_y = vm->vfront_porch + vm->vback_porch + vm->vsync_len +
1329021c317SLaurentiu Palcu vm->vactive - 1;
1339021c317SLaurentiu Palcu
1349021c317SLaurentiu Palcu dcss_ss_write(ss, (lrc_y << LRC_Y_POS) | lrc_x, DCSS_SS_DISPLAY);
1359021c317SLaurentiu Palcu
1369021c317SLaurentiu Palcu hsync_start = vm->hfront_porch + vm->hback_porch + vm->hsync_len +
1379021c317SLaurentiu Palcu vm->hactive - 1;
1389021c317SLaurentiu Palcu hsync_end = vm->hsync_len - 1;
1399021c317SLaurentiu Palcu
1409021c317SLaurentiu Palcu dcss_ss_write(ss, (phsync ? SYNC_POL : 0) |
1419021c317SLaurentiu Palcu ((u32)hsync_end << SYNC_END_POS) | hsync_start,
1429021c317SLaurentiu Palcu DCSS_SS_HSYNC);
1439021c317SLaurentiu Palcu
1449021c317SLaurentiu Palcu vsync_start = vm->vfront_porch - 1;
1459021c317SLaurentiu Palcu vsync_end = vm->vfront_porch + vm->vsync_len - 1;
1469021c317SLaurentiu Palcu
1479021c317SLaurentiu Palcu dcss_ss_write(ss, (pvsync ? SYNC_POL : 0) |
1489021c317SLaurentiu Palcu ((u32)vsync_end << SYNC_END_POS) | vsync_start,
1499021c317SLaurentiu Palcu DCSS_SS_VSYNC);
1509021c317SLaurentiu Palcu
1519021c317SLaurentiu Palcu de_ulc_x = vm->hsync_len + vm->hback_porch - 1;
1529021c317SLaurentiu Palcu de_ulc_y = vm->vsync_len + vm->vfront_porch + vm->vback_porch;
1539021c317SLaurentiu Palcu
1549021c317SLaurentiu Palcu dcss_ss_write(ss, SYNC_POL | ((u32)de_ulc_y << ULC_Y_POS) | de_ulc_x,
1559021c317SLaurentiu Palcu DCSS_SS_DE_ULC);
1569021c317SLaurentiu Palcu
1579021c317SLaurentiu Palcu de_lrc_x = vm->hsync_len + vm->hback_porch + vm->hactive - 1;
1589021c317SLaurentiu Palcu de_lrc_y = vm->vsync_len + vm->vfront_porch + vm->vback_porch +
1599021c317SLaurentiu Palcu vm->vactive - 1;
1609021c317SLaurentiu Palcu
1619021c317SLaurentiu Palcu dcss_ss_write(ss, (de_lrc_y << LRC_Y_POS) | de_lrc_x, DCSS_SS_DE_LRC);
1629021c317SLaurentiu Palcu }
1639021c317SLaurentiu Palcu
dcss_ss_enable(struct dcss_ss * ss)1649021c317SLaurentiu Palcu void dcss_ss_enable(struct dcss_ss *ss)
1659021c317SLaurentiu Palcu {
1669021c317SLaurentiu Palcu dcss_ss_write(ss, RUN_EN, DCSS_SS_SYS_CTRL);
1679021c317SLaurentiu Palcu ss->in_use = true;
1689021c317SLaurentiu Palcu }
1699021c317SLaurentiu Palcu
dcss_ss_shutoff(struct dcss_ss * ss)1709021c317SLaurentiu Palcu void dcss_ss_shutoff(struct dcss_ss *ss)
1719021c317SLaurentiu Palcu {
1729021c317SLaurentiu Palcu dcss_writel(0, ss->base_reg + DCSS_SS_SYS_CTRL);
1739021c317SLaurentiu Palcu ss->in_use = false;
1749021c317SLaurentiu Palcu }
175