1*9021c317SLaurentiu Palcu // SPDX-License-Identifier: GPL-2.0
2*9021c317SLaurentiu Palcu /*
3*9021c317SLaurentiu Palcu * Copyright 2019 NXP.
4*9021c317SLaurentiu Palcu */
5*9021c317SLaurentiu Palcu
6*9021c317SLaurentiu Palcu #include <linux/device.h>
7*9021c317SLaurentiu Palcu #include <linux/slab.h>
8*9021c317SLaurentiu Palcu
9*9021c317SLaurentiu Palcu #include "dcss-dev.h"
10*9021c317SLaurentiu Palcu
11*9021c317SLaurentiu Palcu #define DCSS_SS_SYS_CTRL 0x00
12*9021c317SLaurentiu Palcu #define RUN_EN BIT(0)
13*9021c317SLaurentiu Palcu #define DCSS_SS_DISPLAY 0x10
14*9021c317SLaurentiu Palcu #define LRC_X_POS 0
15*9021c317SLaurentiu Palcu #define LRC_X_MASK GENMASK(12, 0)
16*9021c317SLaurentiu Palcu #define LRC_Y_POS 16
17*9021c317SLaurentiu Palcu #define LRC_Y_MASK GENMASK(28, 16)
18*9021c317SLaurentiu Palcu #define DCSS_SS_HSYNC 0x20
19*9021c317SLaurentiu Palcu #define DCSS_SS_VSYNC 0x30
20*9021c317SLaurentiu Palcu #define SYNC_START_POS 0
21*9021c317SLaurentiu Palcu #define SYNC_START_MASK GENMASK(12, 0)
22*9021c317SLaurentiu Palcu #define SYNC_END_POS 16
23*9021c317SLaurentiu Palcu #define SYNC_END_MASK GENMASK(28, 16)
24*9021c317SLaurentiu Palcu #define SYNC_POL BIT(31)
25*9021c317SLaurentiu Palcu #define DCSS_SS_DE_ULC 0x40
26*9021c317SLaurentiu Palcu #define ULC_X_POS 0
27*9021c317SLaurentiu Palcu #define ULC_X_MASK GENMASK(12, 0)
28*9021c317SLaurentiu Palcu #define ULC_Y_POS 16
29*9021c317SLaurentiu Palcu #define ULC_Y_MASK GENMASK(28, 16)
30*9021c317SLaurentiu Palcu #define ULC_POL BIT(31)
31*9021c317SLaurentiu Palcu #define DCSS_SS_DE_LRC 0x50
32*9021c317SLaurentiu Palcu #define DCSS_SS_MODE 0x60
33*9021c317SLaurentiu Palcu #define PIPE_MODE_POS 0
34*9021c317SLaurentiu Palcu #define PIPE_MODE_MASK GENMASK(1, 0)
35*9021c317SLaurentiu Palcu #define DCSS_SS_COEFF 0x70
36*9021c317SLaurentiu Palcu #define HORIZ_A_POS 0
37*9021c317SLaurentiu Palcu #define HORIZ_A_MASK GENMASK(3, 0)
38*9021c317SLaurentiu Palcu #define HORIZ_B_POS 4
39*9021c317SLaurentiu Palcu #define HORIZ_B_MASK GENMASK(7, 4)
40*9021c317SLaurentiu Palcu #define HORIZ_C_POS 8
41*9021c317SLaurentiu Palcu #define HORIZ_C_MASK GENMASK(11, 8)
42*9021c317SLaurentiu Palcu #define HORIZ_H_NORM_POS 12
43*9021c317SLaurentiu Palcu #define HORIZ_H_NORM_MASK GENMASK(14, 12)
44*9021c317SLaurentiu Palcu #define VERT_A_POS 16
45*9021c317SLaurentiu Palcu #define VERT_A_MASK GENMASK(19, 16)
46*9021c317SLaurentiu Palcu #define VERT_B_POS 20
47*9021c317SLaurentiu Palcu #define VERT_B_MASK GENMASK(23, 20)
48*9021c317SLaurentiu Palcu #define VERT_C_POS 24
49*9021c317SLaurentiu Palcu #define VERT_C_MASK GENMASK(27, 24)
50*9021c317SLaurentiu Palcu #define VERT_H_NORM_POS 28
51*9021c317SLaurentiu Palcu #define VERT_H_NORM_MASK GENMASK(30, 28)
52*9021c317SLaurentiu Palcu #define DCSS_SS_CLIP_CB 0x80
53*9021c317SLaurentiu Palcu #define DCSS_SS_CLIP_CR 0x90
54*9021c317SLaurentiu Palcu #define CLIP_MIN_POS 0
55*9021c317SLaurentiu Palcu #define CLIP_MIN_MASK GENMASK(9, 0)
56*9021c317SLaurentiu Palcu #define CLIP_MAX_POS 0
57*9021c317SLaurentiu Palcu #define CLIP_MAX_MASK GENMASK(23, 16)
58*9021c317SLaurentiu Palcu #define DCSS_SS_INTER_MODE 0xA0
59*9021c317SLaurentiu Palcu #define INT_EN BIT(0)
60*9021c317SLaurentiu Palcu #define VSYNC_SHIFT BIT(1)
61*9021c317SLaurentiu Palcu
62*9021c317SLaurentiu Palcu struct dcss_ss {
63*9021c317SLaurentiu Palcu struct device *dev;
64*9021c317SLaurentiu Palcu void __iomem *base_reg;
65*9021c317SLaurentiu Palcu u32 base_ofs;
66*9021c317SLaurentiu Palcu
67*9021c317SLaurentiu Palcu struct dcss_ctxld *ctxld;
68*9021c317SLaurentiu Palcu u32 ctx_id;
69*9021c317SLaurentiu Palcu
70*9021c317SLaurentiu Palcu bool in_use;
71*9021c317SLaurentiu Palcu };
72*9021c317SLaurentiu Palcu
dcss_ss_write(struct dcss_ss * ss,u32 val,u32 ofs)73*9021c317SLaurentiu Palcu static void dcss_ss_write(struct dcss_ss *ss, u32 val, u32 ofs)
74*9021c317SLaurentiu Palcu {
75*9021c317SLaurentiu Palcu if (!ss->in_use)
76*9021c317SLaurentiu Palcu dcss_writel(val, ss->base_reg + ofs);
77*9021c317SLaurentiu Palcu
78*9021c317SLaurentiu Palcu dcss_ctxld_write(ss->ctxld, ss->ctx_id, val,
79*9021c317SLaurentiu Palcu ss->base_ofs + ofs);
80*9021c317SLaurentiu Palcu }
81*9021c317SLaurentiu Palcu
dcss_ss_init(struct dcss_dev * dcss,unsigned long ss_base)82*9021c317SLaurentiu Palcu int dcss_ss_init(struct dcss_dev *dcss, unsigned long ss_base)
83*9021c317SLaurentiu Palcu {
84*9021c317SLaurentiu Palcu struct dcss_ss *ss;
85*9021c317SLaurentiu Palcu
86*9021c317SLaurentiu Palcu ss = kzalloc(sizeof(*ss), GFP_KERNEL);
87*9021c317SLaurentiu Palcu if (!ss)
88*9021c317SLaurentiu Palcu return -ENOMEM;
89*9021c317SLaurentiu Palcu
90*9021c317SLaurentiu Palcu dcss->ss = ss;
91*9021c317SLaurentiu Palcu ss->dev = dcss->dev;
92*9021c317SLaurentiu Palcu ss->ctxld = dcss->ctxld;
93*9021c317SLaurentiu Palcu
94*9021c317SLaurentiu Palcu ss->base_reg = ioremap(ss_base, SZ_4K);
95*9021c317SLaurentiu Palcu if (!ss->base_reg) {
96*9021c317SLaurentiu Palcu dev_err(dcss->dev, "ss: unable to remap ss base\n");
97*9021c317SLaurentiu Palcu kfree(ss);
98*9021c317SLaurentiu Palcu return -ENOMEM;
99*9021c317SLaurentiu Palcu }
100*9021c317SLaurentiu Palcu
101*9021c317SLaurentiu Palcu ss->base_ofs = ss_base;
102*9021c317SLaurentiu Palcu ss->ctx_id = CTX_SB_HP;
103*9021c317SLaurentiu Palcu
104*9021c317SLaurentiu Palcu return 0;
105*9021c317SLaurentiu Palcu }
106*9021c317SLaurentiu Palcu
dcss_ss_exit(struct dcss_ss * ss)107*9021c317SLaurentiu Palcu void dcss_ss_exit(struct dcss_ss *ss)
108*9021c317SLaurentiu Palcu {
109*9021c317SLaurentiu Palcu /* stop SS */
110*9021c317SLaurentiu Palcu dcss_writel(0, ss->base_reg + DCSS_SS_SYS_CTRL);
111*9021c317SLaurentiu Palcu
112*9021c317SLaurentiu Palcu if (ss->base_reg)
113*9021c317SLaurentiu Palcu iounmap(ss->base_reg);
114*9021c317SLaurentiu Palcu
115*9021c317SLaurentiu Palcu kfree(ss);
116*9021c317SLaurentiu Palcu }
117*9021c317SLaurentiu Palcu
dcss_ss_subsam_set(struct dcss_ss * ss)118*9021c317SLaurentiu Palcu void dcss_ss_subsam_set(struct dcss_ss *ss)
119*9021c317SLaurentiu Palcu {
120*9021c317SLaurentiu Palcu dcss_ss_write(ss, 0x41614161, DCSS_SS_COEFF);
121*9021c317SLaurentiu Palcu dcss_ss_write(ss, 0, DCSS_SS_MODE);
122*9021c317SLaurentiu Palcu dcss_ss_write(ss, 0x03ff0000, DCSS_SS_CLIP_CB);
123*9021c317SLaurentiu Palcu dcss_ss_write(ss, 0x03ff0000, DCSS_SS_CLIP_CR);
124*9021c317SLaurentiu Palcu }
125*9021c317SLaurentiu Palcu
dcss_ss_sync_set(struct dcss_ss * ss,struct videomode * vm,bool phsync,bool pvsync)126*9021c317SLaurentiu Palcu void dcss_ss_sync_set(struct dcss_ss *ss, struct videomode *vm,
127*9021c317SLaurentiu Palcu bool phsync, bool pvsync)
128*9021c317SLaurentiu Palcu {
129*9021c317SLaurentiu Palcu u16 lrc_x, lrc_y;
130*9021c317SLaurentiu Palcu u16 hsync_start, hsync_end;
131*9021c317SLaurentiu Palcu u16 vsync_start, vsync_end;
132*9021c317SLaurentiu Palcu u16 de_ulc_x, de_ulc_y;
133*9021c317SLaurentiu Palcu u16 de_lrc_x, de_lrc_y;
134*9021c317SLaurentiu Palcu
135*9021c317SLaurentiu Palcu lrc_x = vm->hfront_porch + vm->hback_porch + vm->hsync_len +
136*9021c317SLaurentiu Palcu vm->hactive - 1;
137*9021c317SLaurentiu Palcu lrc_y = vm->vfront_porch + vm->vback_porch + vm->vsync_len +
138*9021c317SLaurentiu Palcu vm->vactive - 1;
139*9021c317SLaurentiu Palcu
140*9021c317SLaurentiu Palcu dcss_ss_write(ss, (lrc_y << LRC_Y_POS) | lrc_x, DCSS_SS_DISPLAY);
141*9021c317SLaurentiu Palcu
142*9021c317SLaurentiu Palcu hsync_start = vm->hfront_porch + vm->hback_porch + vm->hsync_len +
143*9021c317SLaurentiu Palcu vm->hactive - 1;
144*9021c317SLaurentiu Palcu hsync_end = vm->hsync_len - 1;
145*9021c317SLaurentiu Palcu
146*9021c317SLaurentiu Palcu dcss_ss_write(ss, (phsync ? SYNC_POL : 0) |
147*9021c317SLaurentiu Palcu ((u32)hsync_end << SYNC_END_POS) | hsync_start,
148*9021c317SLaurentiu Palcu DCSS_SS_HSYNC);
149*9021c317SLaurentiu Palcu
150*9021c317SLaurentiu Palcu vsync_start = vm->vfront_porch - 1;
151*9021c317SLaurentiu Palcu vsync_end = vm->vfront_porch + vm->vsync_len - 1;
152*9021c317SLaurentiu Palcu
153*9021c317SLaurentiu Palcu dcss_ss_write(ss, (pvsync ? SYNC_POL : 0) |
154*9021c317SLaurentiu Palcu ((u32)vsync_end << SYNC_END_POS) | vsync_start,
155*9021c317SLaurentiu Palcu DCSS_SS_VSYNC);
156*9021c317SLaurentiu Palcu
157*9021c317SLaurentiu Palcu de_ulc_x = vm->hsync_len + vm->hback_porch - 1;
158*9021c317SLaurentiu Palcu de_ulc_y = vm->vsync_len + vm->vfront_porch + vm->vback_porch;
159*9021c317SLaurentiu Palcu
160*9021c317SLaurentiu Palcu dcss_ss_write(ss, SYNC_POL | ((u32)de_ulc_y << ULC_Y_POS) | de_ulc_x,
161*9021c317SLaurentiu Palcu DCSS_SS_DE_ULC);
162*9021c317SLaurentiu Palcu
163*9021c317SLaurentiu Palcu de_lrc_x = vm->hsync_len + vm->hback_porch + vm->hactive - 1;
164*9021c317SLaurentiu Palcu de_lrc_y = vm->vsync_len + vm->vfront_porch + vm->vback_porch +
165*9021c317SLaurentiu Palcu vm->vactive - 1;
166*9021c317SLaurentiu Palcu
167*9021c317SLaurentiu Palcu dcss_ss_write(ss, (de_lrc_y << LRC_Y_POS) | de_lrc_x, DCSS_SS_DE_LRC);
168*9021c317SLaurentiu Palcu }
169*9021c317SLaurentiu Palcu
dcss_ss_enable(struct dcss_ss * ss)170*9021c317SLaurentiu Palcu void dcss_ss_enable(struct dcss_ss *ss)
171*9021c317SLaurentiu Palcu {
172*9021c317SLaurentiu Palcu dcss_ss_write(ss, RUN_EN, DCSS_SS_SYS_CTRL);
173*9021c317SLaurentiu Palcu ss->in_use = true;
174*9021c317SLaurentiu Palcu }
175*9021c317SLaurentiu Palcu
dcss_ss_shutoff(struct dcss_ss * ss)176*9021c317SLaurentiu Palcu void dcss_ss_shutoff(struct dcss_ss *ss)
177*9021c317SLaurentiu Palcu {
178*9021c317SLaurentiu Palcu dcss_writel(0, ss->base_reg + DCSS_SS_SYS_CTRL);
179*9021c317SLaurentiu Palcu ss->in_use = false;
180*9021c317SLaurentiu Palcu }
181