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