1 /*
2 * Rockchip isp1 driver
3 *
4 * Copyright (C) 2017 Rockchip Electronics Co., Ltd.
5 *
6 * This software is available to you under a choice of one of two
7 * licenses. You may choose to be licensed under the terms of the GNU
8 * General Public License (GPL) Version 2, available from the file
9 * COPYING in the main directory of this source tree, or the
10 * OpenIB.org BSD license below:
11 *
12 * Redistribution and use in source and binary forms, with or
13 * without modification, are permitted provided that the following
14 * conditions are met:
15 *
16 * - Redistributions of source code must retain the above
17 * copyright notice, this list of conditions and the following
18 * disclaimer.
19 *
20 * - Redistributions in binary form must reproduce the above
21 * copyright notice, this list of conditions and the following
22 * disclaimer in the documentation and/or other materials
23 * provided with the distribution.
24 *
25 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
26 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
27 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
28 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
29 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
30 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
31 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
32 * SOFTWARE.
33 */
34
35 #include <media/v4l2-common.h>
36 #include "regs.h"
37
disable_dcrop(struct rkisp1_stream * stream,bool async)38 void disable_dcrop(struct rkisp1_stream *stream, bool async)
39 {
40 void __iomem *base = stream->ispdev->base_addr;
41 void __iomem *dc_ctrl_addr = base + stream->config->dual_crop.ctrl;
42 u32 dc_ctrl = readl(dc_ctrl_addr);
43 u32 mask = ~(stream->config->dual_crop.yuvmode_mask |
44 stream->config->dual_crop.rawmode_mask);
45 u32 val = dc_ctrl & mask;
46
47 if (async)
48 val |= CIF_DUAL_CROP_GEN_CFG_UPD;
49 else
50 val |= CIF_DUAL_CROP_CFG_UPD;
51 writel(val, dc_ctrl_addr);
52 }
53
config_dcrop(struct rkisp1_stream * stream,struct v4l2_rect * rect,bool async)54 void config_dcrop(struct rkisp1_stream *stream, struct v4l2_rect *rect, bool async)
55 {
56 void __iomem *base = stream->ispdev->base_addr;
57 void __iomem *dc_ctrl_addr = base + stream->config->dual_crop.ctrl;
58 u32 dc_ctrl = readl(dc_ctrl_addr);
59
60 writel(rect->left, base + stream->config->dual_crop.h_offset);
61 writel(rect->top, base + stream->config->dual_crop.v_offset);
62 writel(rect->width, base + stream->config->dual_crop.h_size);
63 writel(rect->height, base + stream->config->dual_crop.v_size);
64 dc_ctrl |= stream->config->dual_crop.yuvmode_mask;
65 if (async)
66 dc_ctrl |= CIF_DUAL_CROP_GEN_CFG_UPD;
67 else
68 dc_ctrl |= CIF_DUAL_CROP_CFG_UPD;
69 writel(dc_ctrl, dc_ctrl_addr);
70 }
71
dump_rsz_regs(struct rkisp1_stream * stream)72 void dump_rsz_regs(struct rkisp1_stream *stream)
73 {
74 void __iomem *base = stream->ispdev->base_addr;
75
76 pr_info("RSZ_CTRL 0x%08x/0x%08x\n"
77 "RSZ_SCALE_HY %d/%d\n"
78 "RSZ_SCALE_HCB %d/%d\n"
79 "RSZ_SCALE_HCR %d/%d\n"
80 "RSZ_SCALE_VY %d/%d\n"
81 "RSZ_SCALE_VC %d/%d\n"
82 "RSZ_PHASE_HY %d/%d\n"
83 "RSZ_PHASE_HC %d/%d\n"
84 "RSZ_PHASE_VY %d/%d\n"
85 "RSZ_PHASE_VC %d/%d\n",
86 readl(base + stream->config->rsz.ctrl),
87 readl(base + stream->config->rsz.ctrl_shd),
88 readl(base + stream->config->rsz.scale_hy),
89 readl(base + stream->config->rsz.scale_hy_shd),
90 readl(base + stream->config->rsz.scale_hcb),
91 readl(base + stream->config->rsz.scale_hcb_shd),
92 readl(base + stream->config->rsz.scale_hcr),
93 readl(base + stream->config->rsz.scale_hcr_shd),
94 readl(base + stream->config->rsz.scale_vy),
95 readl(base + stream->config->rsz.scale_vy_shd),
96 readl(base + stream->config->rsz.scale_vc),
97 readl(base + stream->config->rsz.scale_vc_shd),
98 readl(base + stream->config->rsz.phase_hy),
99 readl(base + stream->config->rsz.phase_hy_shd),
100 readl(base + stream->config->rsz.phase_hc),
101 readl(base + stream->config->rsz.phase_hc_shd),
102 readl(base + stream->config->rsz.phase_vy),
103 readl(base + stream->config->rsz.phase_vy_shd),
104 readl(base + stream->config->rsz.phase_vc),
105 readl(base + stream->config->rsz.phase_vc_shd));
106 }
107
update_rsz_shadow(struct rkisp1_stream * stream,bool async)108 static void update_rsz_shadow(struct rkisp1_stream *stream, bool async)
109 {
110 void *addr = stream->ispdev->base_addr + stream->config->rsz.ctrl;
111 u32 ctrl_cfg = readl(addr);
112
113 if (async)
114 writel(CIF_RSZ_CTRL_CFG_UPD_AUTO | ctrl_cfg, addr);
115 else
116 writel(CIF_RSZ_CTRL_CFG_UPD | ctrl_cfg, addr);
117 }
118
set_scale(struct rkisp1_stream * stream,struct v4l2_rect * in_y,struct v4l2_rect * in_c,struct v4l2_rect * out_y,struct v4l2_rect * out_c)119 static void set_scale(struct rkisp1_stream *stream, struct v4l2_rect *in_y,
120 struct v4l2_rect *in_c, struct v4l2_rect *out_y,
121 struct v4l2_rect *out_c)
122 {
123 void __iomem *base = stream->ispdev->base_addr;
124 void __iomem *scale_hy_addr = base + stream->config->rsz.scale_hy;
125 void __iomem *scale_hcr_addr = base + stream->config->rsz.scale_hcr;
126 void __iomem *scale_hcb_addr = base + stream->config->rsz.scale_hcb;
127 void __iomem *scale_vy_addr = base + stream->config->rsz.scale_vy;
128 void __iomem *scale_vc_addr = base + stream->config->rsz.scale_vc;
129 void __iomem *rsz_ctrl_addr = base + stream->config->rsz.ctrl;
130 u32 scale_hy, scale_hc, scale_vy, scale_vc, rsz_ctrl = 0;
131
132 if (in_y->width < out_y->width) {
133 rsz_ctrl |= CIF_RSZ_CTRL_SCALE_HY_ENABLE |
134 CIF_RSZ_CTRL_SCALE_HY_UP;
135 scale_hy = ((in_y->width - 1) * CIF_RSZ_SCALER_FACTOR) /
136 (out_y->width - 1);
137 writel(scale_hy, scale_hy_addr);
138 } else if (in_y->width > out_y->width) {
139 rsz_ctrl |= CIF_RSZ_CTRL_SCALE_HY_ENABLE;
140 scale_hy = ((out_y->width - 1) * CIF_RSZ_SCALER_FACTOR) /
141 (in_y->width - 1) + 1;
142 writel(scale_hy, scale_hy_addr);
143 }
144 if (in_c->width < out_c->width) {
145 rsz_ctrl |= CIF_RSZ_CTRL_SCALE_HC_ENABLE |
146 CIF_RSZ_CTRL_SCALE_HC_UP;
147 scale_hc = ((in_c->width - 1) * CIF_RSZ_SCALER_FACTOR) /
148 (out_c->width - 1);
149 writel(scale_hc, scale_hcb_addr);
150 writel(scale_hc, scale_hcr_addr);
151 } else if (in_c->width > out_c->width) {
152 rsz_ctrl |= CIF_RSZ_CTRL_SCALE_HC_ENABLE;
153 scale_hc = ((out_c->width - 1) * CIF_RSZ_SCALER_FACTOR) /
154 (in_c->width - 1) + 1;
155 writel(scale_hc, scale_hcb_addr);
156 writel(scale_hc, scale_hcr_addr);
157 }
158
159 if (in_y->height < out_y->height) {
160 rsz_ctrl |= CIF_RSZ_CTRL_SCALE_VY_ENABLE |
161 CIF_RSZ_CTRL_SCALE_VY_UP;
162 scale_vy = ((in_y->height - 1) * CIF_RSZ_SCALER_FACTOR) /
163 (out_y->height - 1);
164 writel(scale_vy, scale_vy_addr);
165 } else if (in_y->height > out_y->height) {
166 rsz_ctrl |= CIF_RSZ_CTRL_SCALE_VY_ENABLE;
167 scale_vy = ((out_y->height - 1) * CIF_RSZ_SCALER_FACTOR) /
168 (in_y->height - 1) + 1;
169 writel(scale_vy, scale_vy_addr);
170 }
171
172 if (in_c->height < out_c->height) {
173 rsz_ctrl |= CIF_RSZ_CTRL_SCALE_VC_ENABLE |
174 CIF_RSZ_CTRL_SCALE_VC_UP;
175 scale_vc = ((in_c->height - 1) * CIF_RSZ_SCALER_FACTOR) /
176 (out_c->height - 1);
177 writel(scale_vc, scale_vc_addr);
178 } else if (in_c->height > out_c->height) {
179 rsz_ctrl |= CIF_RSZ_CTRL_SCALE_VC_ENABLE;
180 scale_vc = ((out_c->height - 1) * CIF_RSZ_SCALER_FACTOR) /
181 (in_c->height - 1) + 1;
182 writel(scale_vc, scale_vc_addr);
183 }
184
185 writel(rsz_ctrl, rsz_ctrl_addr);
186 }
187
config_rsz(struct rkisp1_stream * stream,struct v4l2_rect * in_y,struct v4l2_rect * in_c,struct v4l2_rect * out_y,struct v4l2_rect * out_c,bool async)188 void config_rsz(struct rkisp1_stream *stream, struct v4l2_rect *in_y,
189 struct v4l2_rect *in_c, struct v4l2_rect *out_y,
190 struct v4l2_rect *out_c, bool async)
191 {
192 int i = 0;
193
194 /* No phase offset */
195 writel(0, stream->ispdev->base_addr + stream->config->rsz.phase_hy);
196 writel(0, stream->ispdev->base_addr + stream->config->rsz.phase_hc);
197 writel(0, stream->ispdev->base_addr + stream->config->rsz.phase_vy);
198 writel(0, stream->ispdev->base_addr + stream->config->rsz.phase_vc);
199
200 /* Linear interpolation */
201 for (i = 0; i < 64; i++) {
202 writel(i, stream->ispdev->base_addr + stream->config->rsz.scale_lut_addr);
203 writel(i, stream->ispdev->base_addr + stream->config->rsz.scale_lut);
204 }
205
206 set_scale(stream, in_y, in_c, out_y, out_c);
207
208 update_rsz_shadow(stream, async);
209 }
210
disable_rsz(struct rkisp1_stream * stream,bool async)211 void disable_rsz(struct rkisp1_stream *stream, bool async)
212 {
213 writel(0, stream->ispdev->base_addr + stream->config->rsz.ctrl);
214
215 if (!async)
216 update_rsz_shadow(stream, async);
217 }
218
config_mi_ctrl(struct rkisp1_stream * stream,u32 burst)219 void config_mi_ctrl(struct rkisp1_stream *stream, u32 burst)
220 {
221 void __iomem *base = stream->ispdev->base_addr;
222 void __iomem *addr = base + CIF_MI_CTRL;
223 u32 reg;
224
225 reg = readl(addr) & ~GENMASK(19, 16);
226 writel(reg | burst, addr);
227 reg = readl(addr);
228 writel(reg | CIF_MI_CTRL_INIT_BASE_EN, addr);
229 reg = readl(addr);
230 writel(reg | CIF_MI_CTRL_INIT_OFFSET_EN, addr);
231 }
232
mp_is_stream_stopped(void __iomem * base)233 bool mp_is_stream_stopped(void __iomem *base)
234 {
235 int en;
236
237 en = CIF_MI_CTRL_SHD_MP_IN_ENABLED | CIF_MI_CTRL_SHD_RAW_OUT_ENABLED;
238 return !(readl(base + CIF_MI_CTRL_SHD) & en);
239 }
240
sp_is_stream_stopped(void __iomem * base)241 bool sp_is_stream_stopped(void __iomem *base)
242 {
243 return !(readl(base + CIF_MI_CTRL_SHD) & CIF_MI_CTRL_SHD_SP_IN_ENABLED);
244 }
245