1
2
3
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
62struct 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
73static 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(ss->ctxld, ss->ctx_id, val,
79 ss->base_ofs + ofs);
80}
81
82int dcss_ss_init(struct dcss_dev *dcss, unsigned long ss_base)
83{
84 struct dcss_ss *ss;
85
86 ss = kzalloc(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 = ioremap(ss_base, SZ_4K);
95 if (!ss->base_reg) {
96 dev_err(dcss->dev, "ss: unable to remap ss base\n");
97 kfree(ss);
98 return -ENOMEM;
99 }
100
101 ss->base_ofs = ss_base;
102 ss->ctx_id = CTX_SB_HP;
103
104 return 0;
105}
106
107void dcss_ss_exit(struct dcss_ss *ss)
108{
109
110 dcss_writel(0, ss->base_reg + DCSS_SS_SYS_CTRL);
111
112 if (ss->base_reg)
113 iounmap(ss->base_reg);
114
115 kfree(ss);
116}
117
118void dcss_ss_subsam_set(struct dcss_ss *ss)
119{
120 dcss_ss_write(ss, 0x41614161, DCSS_SS_COEFF);
121 dcss_ss_write(ss, 0, DCSS_SS_MODE);
122 dcss_ss_write(ss, 0x03ff0000, DCSS_SS_CLIP_CB);
123 dcss_ss_write(ss, 0x03ff0000, DCSS_SS_CLIP_CR);
124}
125
126void dcss_ss_sync_set(struct dcss_ss *ss, struct videomode *vm,
127 bool phsync, bool pvsync)
128{
129 u16 lrc_x, lrc_y;
130 u16 hsync_start, hsync_end;
131 u16 vsync_start, vsync_end;
132 u16 de_ulc_x, de_ulc_y;
133 u16 de_lrc_x, de_lrc_y;
134
135 lrc_x = vm->hfront_porch + vm->hback_porch + vm->hsync_len +
136 vm->hactive - 1;
137 lrc_y = vm->vfront_porch + vm->vback_porch + vm->vsync_len +
138 vm->vactive - 1;
139
140 dcss_ss_write(ss, (lrc_y << LRC_Y_POS) | lrc_x, DCSS_SS_DISPLAY);
141
142 hsync_start = vm->hfront_porch + vm->hback_porch + vm->hsync_len +
143 vm->hactive - 1;
144 hsync_end = vm->hsync_len - 1;
145
146 dcss_ss_write(ss, (phsync ? SYNC_POL : 0) |
147 ((u32)hsync_end << SYNC_END_POS) | hsync_start,
148 DCSS_SS_HSYNC);
149
150 vsync_start = vm->vfront_porch - 1;
151 vsync_end = vm->vfront_porch + vm->vsync_len - 1;
152
153 dcss_ss_write(ss, (pvsync ? SYNC_POL : 0) |
154 ((u32)vsync_end << SYNC_END_POS) | vsync_start,
155 DCSS_SS_VSYNC);
156
157 de_ulc_x = vm->hsync_len + vm->hback_porch - 1;
158 de_ulc_y = vm->vsync_len + vm->vfront_porch + vm->vback_porch;
159
160 dcss_ss_write(ss, SYNC_POL | ((u32)de_ulc_y << ULC_Y_POS) | de_ulc_x,
161 DCSS_SS_DE_ULC);
162
163 de_lrc_x = vm->hsync_len + vm->hback_porch + vm->hactive - 1;
164 de_lrc_y = vm->vsync_len + vm->vfront_porch + vm->vback_porch +
165 vm->vactive - 1;
166
167 dcss_ss_write(ss, (de_lrc_y << LRC_Y_POS) | de_lrc_x, DCSS_SS_DE_LRC);
168}
169
170void dcss_ss_enable(struct dcss_ss *ss)
171{
172 dcss_ss_write(ss, RUN_EN, DCSS_SS_SYS_CTRL);
173 ss->in_use = true;
174}
175
176void dcss_ss_shutoff(struct dcss_ss *ss)
177{
178 dcss_writel(0, ss->base_reg + DCSS_SS_SYS_CTRL);
179 ss->in_use = false;
180}
181