diff --git a/drivers/media/spi/Kconfig b/drivers/media/spi/Kconfig index 857ef4ace6e9..f9acef9720c3 100644 --- a/drivers/media/spi/Kconfig +++ b/drivers/media/spi/Kconfig @@ -15,6 +15,15 @@ config VIDEO_GS1662 help Enable the GS1662 driver which serializes video streams. +config VIDEO_ROCKCHIP_PREISP + tristate "Rockchip Image Signal Pre-processing driver" + depends on VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API && SPI_MASTER + depends on ARCH_ROCKCHIP || COMPILE_TEST + select V4L2_FWNODE + default n + help + Support for Pre-isp on the rockchip SoC. + endmenu endif diff --git a/drivers/media/spi/Makefile b/drivers/media/spi/Makefile index 9f45787d680d..501838805d43 100644 --- a/drivers/media/spi/Makefile +++ b/drivers/media/spi/Makefile @@ -1,5 +1,7 @@ # SPDX-License-Identifier: GPL-2.0-only obj-$(CONFIG_VIDEO_GS1662) += gs1662.o obj-$(CONFIG_CXD2880_SPI_DRV) += cxd2880-spi.o +obj-$(CONFIG_VIDEO_ROCKCHIP_PREISP) += rk1608.o rk1608_dphy.o +rk1608-objs += rk1608_dev.o rk1608_core.o ccflags-y += -I $(srctree)/drivers/media/dvb-frontends/cxd2880 diff --git a/drivers/media/spi/rk1608_core.c b/drivers/media/spi/rk1608_core.c index cf2c3f6c10a6..f19188bdc22b 100644 --- a/drivers/media/spi/rk1608_core.c +++ b/drivers/media/spi/rk1608_core.c @@ -580,16 +580,19 @@ static int rk1608_msg_init_sensor(struct rk1608_state *pdata, static int rk1608_msg_init_dsp_time(struct rk1608_state *pdata, struct msg_init_dsp_time *msg, int id) { - struct timeval tv; + u64 usecs64; + u32 mod; msg->msg_head.size = sizeof(struct msg_init_dsp_time); msg->msg_head.type = id_msg_sys_time_set_t; msg->msg_head.id.camera_id = id; msg->msg_head.mux.sync = 0; - do_gettimeofday(&tv); - msg->tv_sec = tv.tv_sec; - msg->tv_usec = tv.tv_usec; + usecs64 = ktime_to_us(ktime_get()); + + mod = do_div(usecs64, USEC_PER_MSEC); + msg->tv_usec = mod; + msg->tv_sec = usecs64; return rk1608_send_msg_to_dsp(pdata, &msg->msg_head); } @@ -1030,6 +1033,9 @@ static int rk1608_power_on(struct rk1608_state *pdata) struct spi_device *spi = pdata->spi; int ret = 0; + if (pdata->pwren_gpio) + gpiod_direction_output(pdata->pwren_gpio, 1); + if (!IS_ERR(pdata->mclk)) { ret = clk_set_rate(pdata->mclk, RK1608_MCLK_RATE); if (ret < 0) @@ -1094,6 +1100,9 @@ static int rk1608_power_off(struct rk1608_state *pdata) gpiod_direction_output(pdata->reset_gpio, 0); rk1608_cs_set_value(pdata, 0); + if (pdata->pwren_gpio) + gpiod_direction_output(pdata->pwren_gpio, 0); + if (!IS_ERR(pdata->mclk)) clk_disable_unprepare(pdata->mclk); @@ -1880,7 +1889,6 @@ static int preisp_file_import_data(struct rk1608_state *pdata, struct msg *msg) unsigned int file_size = 0; unsigned int write_size = 0; char *file_data = NULL; - struct kstat *stat; struct msg_xfile *xfile; char *ref_data_path = REF_DATA_PATH; @@ -1899,30 +1907,21 @@ static int preisp_file_import_data(struct rk1608_state *pdata, struct msg *msg) return -EFAULT; } - stat = kmalloc(sizeof(*stat), GFP_KERNEL); - if (!stat) { - ret = -ENOMEM; - goto err; - } - - vfs_stat(file_path, stat); - - file_size = stat->size; - file_size = (file_size+0x3)&(~0x3); - dev_info(pdata->dev, "start import %s to addr:0x%x size:%d\n", - file_path, xfile->addr, file_size); + file_path, xfile->addr, xfile->data_size); - file_data = vmalloc(file_size); + file_data = vmalloc(xfile->data_size); if (!file_data) { ret = -ENOMEM; goto err; } - ret = kernel_read(fp, file_data, file_size, &pos); - if (ret <= 0) + file_size = kernel_read(fp, file_data, xfile->data_size, &pos); + if (file_size <= 0) { dev_err(pdata->dev, "%s: read error: ret=%d\n", __func__, ret); + goto err; + } write_size = (file_size <= xfile->data_size)?file_size:xfile->data_size; if (file_size != xfile->data_size) @@ -1946,7 +1945,6 @@ static int preisp_file_import_data(struct rk1608_state *pdata, struct msg *msg) xfile->path, xfile->addr, file_size); err: - kfree(stat); if (file_data) vfree(file_data); if (fp) @@ -2299,7 +2297,7 @@ static void rk1608_dispatch_received_msg(struct rk1608_state *pdata, #define PREISP_DCROP_CALIB_RATIO 192 #define PREISP_DCROP_CALIB_XOFFSET 196 #define PREISP_DCROP_CALIB_YOFFSET 198 -static int rk1608_get_dcrop_cfg(struct v4l2_rect *crop_in, +int rk1608_get_dcrop_cfg(struct v4l2_rect *crop_in, struct v4l2_rect *crop_out) { struct file *fp; diff --git a/drivers/media/spi/rk1608_core.h b/drivers/media/spi/rk1608_core.h index 92de1f562553..3510b40701b5 100644 --- a/drivers/media/spi/rk1608_core.h +++ b/drivers/media/spi/rk1608_core.h @@ -635,4 +635,6 @@ void rk1608_set_spi_speed(struct rk1608_state *pdata, u32 hz); int rk1608_set_log_level(struct rk1608_state *pdata, int level); +int rk1608_get_dcrop_cfg(struct v4l2_rect *crop_in, + struct v4l2_rect *crop_out); #endif diff --git a/drivers/media/spi/rk1608_dphy.c b/drivers/media/spi/rk1608_dphy.c index 0740bd91458e..4d8616317bb2 100644 --- a/drivers/media/spi/rk1608_dphy.c +++ b/drivers/media/spi/rk1608_dphy.c @@ -27,6 +27,7 @@ #include #include #include "rk1608_dphy.h" +#include #define RK1608_DPHY_NAME "RK1608-dphy" @@ -201,9 +202,9 @@ static int rk1608_set_fmt(struct v4l2_subdev *sd, pdata->fmt_inf_idx = idx; + pdata->rk1608_sd->grp_id = pdata->sd.grp_id; v4l2_subdev_call(pdata->rk1608_sd, pad, set_fmt, cfg, fmt); - pdata->rk1608_sd->grp_id = pdata->sd.grp_id; remote_ctrl = v4l2_ctrl_find(pdata->rk1608_sd->ctrl_handler, V4L2_CID_HBLANK); if (remote_ctrl) { @@ -249,7 +250,7 @@ static int rk1608_s_frame_interval(struct v4l2_subdev *sd, return 0; } -static int rk1608_g_mbus_config(struct v4l2_subdev *sd, +static int rk1608_g_mbus_config(struct v4l2_subdev *sd, unsigned int pad_id, struct v4l2_mbus_config *config) { @@ -260,7 +261,7 @@ static int rk1608_g_mbus_config(struct v4l2_subdev *sd, V4L2_MBUS_CSI2_CHANNEL_0 | V4L2_MBUS_CSI2_CONTINUOUS_CLOCK; - config->type = V4L2_MBUS_CSI2; + config->type = V4L2_MBUS_CSI2_DPHY; config->flags = val; return 0; @@ -310,7 +311,7 @@ static long rk1608_compat_ioctl32(struct v4l2_subdev *sd, struct preisp_hdrae_exp_s hdrae_exp; struct rkmodule_inf *inf; struct rkmodule_awb_cfg *cfg; - long ret; + long ret = -EFAULT; switch (cmd) { case PREISP_CMD_SET_HDRAE_EXP: @@ -327,7 +328,10 @@ static long rk1608_compat_ioctl32(struct v4l2_subdev *sd, ret = rk1608_ioctl(sd, cmd, inf); if (!ret) - ret = copy_to_user(up, inf, sizeof(*inf)); + if (copy_to_user(up, inf, sizeof(*inf))) { + kfree(inf); + return -EFAULT; + } kfree(inf); break; case RKMODULE_AWB_CFG: @@ -389,6 +393,47 @@ static int rk1608_set_ctrl(struct v4l2_ctrl *ctrl) return ret; } +static int rk1608_get_selection(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_selection *sel) +{ + struct rk1608_dphy *pdata = to_state(sd); + u32 idx = pdata->fmt_inf_idx; + + if (sel->target != V4L2_SEL_TGT_CROP_BOUNDS) + return -EINVAL; + + sel->r.left = 0; + sel->r.top = 0; + sel->r.width = pdata->fmt_inf[idx].mf.width; + sel->r.height = pdata->fmt_inf[idx].mf.height; + + return 0; +} + +static int rk1608_enum_frame_interval(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_frame_interval_enum *fie) +{ + struct rk1608_dphy *pdata = to_state(sd); + u32 idx = pdata->fmt_inf_idx; + int ret = 0; + struct v4l2_fract max_fps = { + .numerator = 10000, + .denominator = 300000, + }; + + if (fie->index >= pdata->fmt_inf_num) + return -EINVAL; + + fie->code = pdata->fmt_inf[idx].mf.code; + fie->width = pdata->fmt_inf[idx].mf.width; + fie->height = pdata->fmt_inf[idx].mf.height; + fie->interval = max_fps; + + return ret; +} + static const struct v4l2_ctrl_ops rk1608_ctrl_ops = { .g_volatile_ctrl = rk1608_g_volatile_ctrl, .s_ctrl = rk1608_set_ctrl, @@ -511,7 +556,6 @@ static const struct v4l2_subdev_video_ops rk1608_subdev_video_ops = { .s_stream = rk1608_s_stream, .g_frame_interval = rk1608_g_frame_interval, .s_frame_interval = rk1608_s_frame_interval, - .g_mbus_config = rk1608_g_mbus_config, }; static const struct v4l2_subdev_pad_ops rk1608_subdev_pad_ops = { @@ -519,6 +563,9 @@ static const struct v4l2_subdev_pad_ops rk1608_subdev_pad_ops = { .enum_frame_size = rk1608_enum_frame_sizes, .get_fmt = rk1608_get_fmt, .set_fmt = rk1608_set_fmt, + .get_mbus_config = rk1608_g_mbus_config, + .get_selection = rk1608_get_selection, + .enum_frame_interval = rk1608_enum_frame_interval, }; static const struct v4l2_subdev_core_ops rk1608_core_ops = {