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