From 08330d500d8c691e34f5a2a1582030f1bcb924a4 Mon Sep 17 00:00:00 2001 From: Zefa Chen Date: Wed, 7 Sep 2022 15:38:48 +0800 Subject: [PATCH 1/3] phy: rockchip: csi2-dphy: logic node of mipi phy can control all hw of mipi phy Signed-off-by: Zefa Chen Change-Id: I30cc62cc1d28c4219e9e5c5ccd77fa9f589e63af --- .../rockchip/phy-rockchip-csi2-dphy-common.h | 15 +- drivers/phy/rockchip/phy-rockchip-csi2-dphy.c | 810 ++++++++++++------ .../phy/rockchip/phy-rockchip-samsung-dcphy.c | 10 +- 3 files changed, 548 insertions(+), 287 deletions(-) diff --git a/drivers/phy/rockchip/phy-rockchip-csi2-dphy-common.h b/drivers/phy/rockchip/phy-rockchip-csi2-dphy-common.h index 0ec812bcb014..3811d6fe6283 100644 --- a/drivers/phy/rockchip/phy-rockchip-csi2-dphy-common.h +++ b/drivers/phy/rockchip/phy-rockchip-csi2-dphy-common.h @@ -9,10 +9,15 @@ #define _PHY_ROCKCHIP_CSI2_DPHY_COMMON_H_ #include +#include #define PHY_MAX 16 #define MAX_DEV_NAME_LEN 32 +#define MAX_SAMSUNG_PHY_NUM 2 + +#define MAX_INNO_PHY_NUM 2 + /* add new chip id in tail by time order */ enum csi2_dphy_chip_id { CHIP_ID_RK3568 = 0x0, @@ -59,14 +64,18 @@ struct samsung_mipi_dcphy; struct dphy_drv_data { const char dev_name[MAX_DEV_NAME_LEN]; - enum csi2_dphy_vendor vendor; + enum csi2_dphy_chip_id chip_id; + char num_inno_phy; + char num_samsung_phy; }; struct csi2_dphy { struct device *dev; struct list_head list; struct csi2_dphy_hw *dphy_hw; + struct csi2_dphy_hw *dphy_hw_group[MAX_INNO_PHY_NUM]; struct samsung_mipi_dcphy *samsung_phy; + struct samsung_mipi_dcphy *samsung_phy_group[MAX_SAMSUNG_PHY_NUM]; struct v4l2_async_notifier notifier; struct v4l2_subdev sd; struct mutex mutex; /* lock for updating protection */ @@ -75,8 +84,10 @@ struct csi2_dphy { u64 data_rate_mbps; int num_sensors; int phy_index; + struct rkcif_csi_info csi_info; + void *phy_hw[RKMODULE_MULTI_DEV_NUM]; bool is_streaming; - enum csi2_dphy_lane_mode lane_mode; + int lane_mode; const struct dphy_drv_data *drv_data; struct rkmodule_csi_dphy_param dphy_param; }; diff --git a/drivers/phy/rockchip/phy-rockchip-csi2-dphy.c b/drivers/phy/rockchip/phy-rockchip-csi2-dphy.c index 81827de21d9c..1fff30da8651 100644 --- a/drivers/phy/rockchip/phy-rockchip-csi2-dphy.c +++ b/drivers/phy/rockchip/phy-rockchip-csi2-dphy.c @@ -25,6 +25,17 @@ #include "phy-rockchip-csi2-dphy-common.h" #include "phy-rockchip-samsung-dcphy.h" +static struct rkmodule_csi_dphy_param rk3588_dcphy_param = { + .vendor = PHY_VENDOR_SAMSUNG, + .lp_vol_ref = 3, + .lp_hys_sw = {3, 0, 0, 0}, + .lp_escclk_pol_sel = {1, 0, 0, 0}, + .skew_data_cal_clk = {0, 3, 3, 3}, + .clk_hs_term_sel = 2, + .data_hs_term_sel = {2, 2, 2, 2}, + .reserved = {0}, +}; + struct sensor_async_subdev { struct v4l2_async_subdev asd; struct v4l2_mbus_config mbus; @@ -42,7 +53,10 @@ static struct v4l2_subdev *get_remote_sensor(struct v4l2_subdev *sd) { struct media_pad *local, *remote; struct media_entity *sensor_me; + struct csi2_dphy *dphy = to_csi2_dphy(sd); + if (dphy->num_sensors == 0) + return NULL; local = &sd->entity.pads[CSI2_DPHY_RX_PAD_SINK]; remote = media_entity_remote_pad(local); if (!remote) { @@ -72,7 +86,7 @@ static int csi2_dphy_get_sensor_data_rate(struct v4l2_subdev *sd) struct v4l2_subdev *sensor_sd = get_remote_sensor(sd); struct v4l2_ctrl *link_freq; struct v4l2_querymenu qm = { .id = V4L2_CID_LINK_FREQ, }; - int ret; + int ret = 0; if (!sensor_sd) return -ENODEV; @@ -101,14 +115,213 @@ static int csi2_dphy_get_sensor_data_rate(struct v4l2_subdev *sd) return 0; } +static int rockchip_csi2_dphy_attach_hw(struct csi2_dphy *dphy, int csi_idx, int index) +{ + struct csi2_dphy_hw *dphy_hw; + struct samsung_mipi_dcphy *dcphy_hw; + struct v4l2_subdev *sensor_sd = get_remote_sensor(&dphy->sd); + struct csi2_sensor *sensor = NULL; + int lanes = 2; + + if (sensor_sd) { + sensor = sd_to_sensor(dphy, sensor_sd); + lanes = sensor->lanes; + } + + if (dphy->drv_data->chip_id == CHIP_ID_RK3568 || + dphy->drv_data->chip_id == CHIP_ID_RV1106) { + dphy_hw = dphy->dphy_hw_group[0]; + mutex_lock(&dphy_hw->mutex); + dphy_hw->dphy_dev[dphy_hw->dphy_dev_num] = dphy; + dphy_hw->dphy_dev_num++; + switch (dphy->phy_index) { + case 0: + dphy->lane_mode = PHY_FULL_MODE; + dphy_hw->lane_mode = LANE_MODE_FULL; + break; + case 1: + dphy->lane_mode = PHY_SPLIT_01; + dphy_hw->lane_mode = LANE_MODE_SPLIT; + break; + case 2: + dphy->lane_mode = PHY_SPLIT_23; + dphy_hw->lane_mode = LANE_MODE_SPLIT; + break; + default: + dphy->lane_mode = PHY_FULL_MODE; + dphy_hw->lane_mode = LANE_MODE_FULL; + break; + } + dphy->dphy_hw = dphy_hw; + dphy->phy_hw[index] = (void *)dphy_hw; + dphy->csi_info.dphy_vendor[index] = PHY_VENDOR_INNO; + mutex_unlock(&dphy_hw->mutex); + } else if (dphy->drv_data->chip_id == CHIP_ID_RK3588) { + if (csi_idx < 2) { + dcphy_hw = dphy->samsung_phy_group[csi_idx]; + mutex_lock(&dcphy_hw->mutex); + dcphy_hw->dphy_dev_num++; + mutex_unlock(&dcphy_hw->mutex); + dphy->samsung_phy = dcphy_hw; + dphy->phy_hw[index] = (void *)dcphy_hw; + dphy->dphy_param = rk3588_dcphy_param; + dphy->csi_info.dphy_vendor[index] = PHY_VENDOR_SAMSUNG; + } else { + dphy_hw = dphy->dphy_hw_group[(csi_idx - 2) / 2]; + mutex_lock(&dphy_hw->mutex); + if (csi_idx == 2 || csi_idx == 4) { + if (lanes == 4) { + dphy->lane_mode = PHY_FULL_MODE; + dphy_hw->lane_mode = LANE_MODE_FULL; + if (csi_idx == 2) + dphy->phy_index = 0; + else + dphy->phy_index = 3; + } else { + dphy->lane_mode = PHY_SPLIT_01; + dphy_hw->lane_mode = LANE_MODE_SPLIT; + if (csi_idx == 2) + dphy->phy_index = 1; + else + dphy->phy_index = 4; + } + } else if (csi_idx == 3 || csi_idx == 5) { + if (lanes == 4) { + dev_info(dphy->dev, "%s csi host%d only support PHY_SPLIT_23\n", + __func__, csi_idx); + mutex_unlock(&dphy_hw->mutex); + return -EINVAL; + } + dphy->lane_mode = PHY_SPLIT_23; + dphy_hw->lane_mode = LANE_MODE_SPLIT; + if (csi_idx == 3) + dphy->phy_index = 2; + else + dphy->phy_index = 5; + } + dphy_hw->dphy_dev_num++; + dphy->dphy_hw = dphy_hw; + dphy->phy_hw[index] = (void *)dphy_hw; + dphy->csi_info.dphy_vendor[index] = PHY_VENDOR_INNO; + mutex_unlock(&dphy_hw->mutex); + } + } else { + dphy_hw = dphy->dphy_hw_group[csi_idx / 2]; + mutex_lock(&dphy_hw->mutex); + if (csi_idx == 0 || csi_idx == 2) { + if (lanes == 4) { + dphy->lane_mode = PHY_FULL_MODE; + dphy_hw->lane_mode = LANE_MODE_FULL; + if (csi_idx == 0) + dphy->phy_index = 0; + else + dphy->phy_index = 3; + } else { + dphy->lane_mode = PHY_SPLIT_01; + dphy_hw->lane_mode = LANE_MODE_SPLIT; + if (csi_idx == 0) + dphy->phy_index = 1; + else + dphy->phy_index = 4; + } + } else if (csi_idx == 1 || csi_idx == 3) { + if (lanes == 4) { + dev_info(dphy->dev, "%s csi host%d only support PHY_SPLIT_23\n", + __func__, csi_idx); + mutex_unlock(&dphy_hw->mutex); + return -EINVAL; + } + dphy->lane_mode = PHY_SPLIT_23; + dphy_hw->lane_mode = LANE_MODE_SPLIT; + if (csi_idx == 1) + dphy->phy_index = 2; + else + dphy->phy_index = 5; + } else { + dev_info(dphy->dev, "%s error csi host%d\n", + __func__, csi_idx); + mutex_unlock(&dphy_hw->mutex); + return -EINVAL; + } + dphy_hw->dphy_dev[dphy_hw->dphy_dev_num] = dphy; + dphy->phy_hw[index] = (void *)dphy_hw; + dphy->csi_info.dphy_vendor[index] = PHY_VENDOR_INNO; + mutex_unlock(&dphy_hw->mutex); + } + + return 0; +} + +static int rockchip_csi2_dphy_detach_hw(struct csi2_dphy *dphy, int csi_idx, int index) +{ + struct csi2_dphy_hw *dphy_hw = NULL; + struct samsung_mipi_dcphy *dcphy_hw = NULL; + struct csi2_dphy *csi2_dphy = NULL; + int i = 0; + + if (dphy->drv_data->chip_id == CHIP_ID_RK3568 || + dphy->drv_data->chip_id == CHIP_ID_RV1106) { + dphy_hw = (struct csi2_dphy_hw *)dphy->phy_hw[index]; + if (!dphy_hw) { + dev_err(dphy->dev, "%s csi_idx %d detach hw failed\n", + __func__, csi_idx); + return -EINVAL; + } + mutex_lock(&dphy_hw->mutex); + for (i = 0; i < dphy_hw->dphy_dev_num; i++) { + csi2_dphy = dphy_hw->dphy_dev[i]; + if (csi2_dphy && + csi2_dphy->phy_index == dphy->phy_index) { + dphy_hw->dphy_dev[i] = NULL; + dphy_hw->dphy_dev_num--; + break; + } + } + mutex_unlock(&dphy_hw->mutex); + } else if (dphy->drv_data->chip_id == CHIP_ID_RK3588) { + if (csi_idx < 2) { + dcphy_hw = (struct samsung_mipi_dcphy *)dphy->phy_hw[index]; + if (!dcphy_hw) { + dev_err(dphy->dev, "%s csi_idx %d detach hw failed\n", + __func__, csi_idx); + return -EINVAL; + } + mutex_lock(&dcphy_hw->mutex); + dcphy_hw->dphy_dev_num--; + mutex_unlock(&dcphy_hw->mutex); + } else { + dphy_hw = (struct csi2_dphy_hw *)dphy->phy_hw[index]; + if (!dphy_hw) { + dev_err(dphy->dev, "%s csi_idx %d detach hw failed\n", + __func__, csi_idx); + return -EINVAL; + } + mutex_lock(&dphy_hw->mutex); + dphy_hw->dphy_dev_num--; + mutex_unlock(&dphy_hw->mutex); + } + } else { + dphy_hw = (struct csi2_dphy_hw *)dphy->phy_hw[index]; + if (!dphy_hw) { + dev_err(dphy->dev, "%s csi_idx %d detach hw failed\n", + __func__, csi_idx); + return -EINVAL; + } + mutex_lock(&dphy_hw->mutex); + dphy_hw->dphy_dev_num--; + mutex_unlock(&dphy_hw->mutex); + } + + return 0; +} + static int csi2_dphy_update_sensor_mbus(struct v4l2_subdev *sd) { struct csi2_dphy *dphy = to_csi2_dphy(sd); struct v4l2_subdev *sensor_sd = get_remote_sensor(sd); struct csi2_sensor *sensor; struct v4l2_mbus_config mbus; - struct rkmodule_bus_config bus_config; - int ret; + int ret = 0; if (!sensor_sd) return -ENODEV; @@ -137,86 +350,83 @@ static int csi2_dphy_update_sensor_mbus(struct v4l2_subdev *sd) default: return -EINVAL; } - if (dphy->drv_data->vendor == PHY_VENDOR_INNO) { - ret = v4l2_subdev_call(sensor_sd, core, ioctl, - RKMODULE_GET_BUS_CONFIG, &bus_config); - if (!ret) { - dev_info(dphy->dev, "phy_mode %d,lane %d\n", - bus_config.bus.phy_mode, bus_config.bus.lanes); - if (bus_config.bus.phy_mode == PHY_FULL_MODE) { - if (dphy->dphy_hw->drv_data->chip_id == CHIP_ID_RK3588 && - dphy->phy_index % 3 == 2) { - dev_err(dphy->dev, "%s dphy%d only use for PHY_SPLIT_23\n", - __func__, dphy->phy_index); - ret = -EINVAL; - } - dphy->lane_mode = LANE_MODE_FULL; - } else if (bus_config.bus.phy_mode == PHY_SPLIT_01) { - if (dphy->dphy_hw->drv_data->chip_id == CHIP_ID_RK3588_DCPHY) { - dev_err(dphy->dev, "%s The chip not support split mode\n", - __func__); - ret = -EINVAL; - } else if (dphy->phy_index % 3 == 2) { - dev_err(dphy->dev, "%s dphy%d only use for PHY_SPLIT_23\n", - __func__, dphy->phy_index); - ret = -EINVAL; - } else { - dphy->lane_mode = LANE_MODE_SPLIT; - } - } else if (bus_config.bus.phy_mode == PHY_SPLIT_23) { - if (dphy->dphy_hw->drv_data->chip_id == CHIP_ID_RK3588_DCPHY) { - dev_err(dphy->dev, "%s The chip not support split mode\n", - __func__); - ret = -EINVAL; - } else if (dphy->phy_index % 3 != 2) { - dev_err(dphy->dev, "%s dphy%d not support PHY_SPLIT_23\n", - __func__, dphy->phy_index); - ret = -EINVAL; - } else { - dphy->lane_mode = LANE_MODE_SPLIT; + + return 0; +} + +static int csi2_dphy_update_config(struct v4l2_subdev *sd) +{ + struct csi2_dphy *dphy = to_csi2_dphy(sd); + struct v4l2_subdev *sensor_sd = get_remote_sensor(sd); + struct rkmodule_csi_dphy_param dphy_param; + struct rkmodule_bus_config bus_config; + int csi_idx = 0; + int ret = 0; + int i = 0; + + for (i = 0; i < dphy->csi_info.csi_num; i++) { + if (dphy->drv_data->chip_id != CHIP_ID_RK3568 && + dphy->drv_data->chip_id != CHIP_ID_RV1106) { + csi_idx = dphy->csi_info.csi_idx[i]; + rockchip_csi2_dphy_attach_hw(dphy, csi_idx, i); + } + if (dphy->csi_info.dphy_vendor[i] == PHY_VENDOR_INNO) { + ret = v4l2_subdev_call(sensor_sd, core, ioctl, + RKMODULE_GET_BUS_CONFIG, &bus_config); + if (!ret) { + dev_info(dphy->dev, "phy_mode %d,lane %d\n", + bus_config.bus.phy_mode, bus_config.bus.lanes); + if (bus_config.bus.phy_mode == PHY_FULL_MODE) { + if (dphy->phy_index % 3 == 2) { + dev_err(dphy->dev, "%s dphy%d only use for PHY_SPLIT_23\n", + __func__, dphy->phy_index); + return -EINVAL; + } + dphy->lane_mode = PHY_FULL_MODE; + dphy->dphy_hw->lane_mode = LANE_MODE_FULL; + } else if (bus_config.bus.phy_mode == PHY_SPLIT_01) { + if (dphy->phy_index % 3 == 2) { + dev_err(dphy->dev, "%s dphy%d only use for PHY_SPLIT_23\n", + __func__, dphy->phy_index); + return -EINVAL; + } + dphy->lane_mode = PHY_SPLIT_01; + dphy->dphy_hw->lane_mode = LANE_MODE_SPLIT; + } else if (bus_config.bus.phy_mode == PHY_SPLIT_23) { + if (dphy->phy_index % 3 != 2) { + dev_err(dphy->dev, "%s dphy%d not support PHY_SPLIT_23\n", + __func__, dphy->phy_index); + return -EINVAL; + } + dphy->lane_mode = PHY_SPLIT_23; + dphy->dphy_hw->lane_mode = LANE_MODE_SPLIT; } } - if (!ret) - dphy->dphy_hw->lane_mode = dphy->lane_mode; - } else { - ret = 0; } } - if (dphy->drv_data->vendor == PHY_VENDOR_SAMSUNG) { - ret = v4l2_subdev_call(sensor_sd, core, ioctl, - RKMODULE_GET_CSI_DPHY_PARAM, - &dphy->dphy_param); - if (ret) { - dev_dbg(dphy->dev, "%s fail to get dphy param, used default value\n", - __func__); - ret = 0; - } - } - return ret; + ret = v4l2_subdev_call(sensor_sd, core, ioctl, + RKMODULE_GET_CSI_DPHY_PARAM, + &dphy_param); + if (!ret) + dphy->dphy_param = dphy_param; + return 0; } static int csi2_dphy_s_stream_start(struct v4l2_subdev *sd) { struct csi2_dphy *dphy = to_csi2_dphy(sd); - struct csi2_dphy_hw *hw = dphy->dphy_hw; - struct samsung_mipi_dcphy *samsung_phy = dphy->samsung_phy; - int ret = 0; + int i = 0; - if (dphy->is_streaming) - return 0; - - ret = csi2_dphy_get_sensor_data_rate(sd); - if (ret < 0) - return ret; - - csi2_dphy_update_sensor_mbus(sd); - - if (dphy->drv_data->vendor == PHY_VENDOR_SAMSUNG) { - if (samsung_phy && samsung_phy->stream_on) - samsung_phy->stream_on(dphy, sd); - } else { - if (hw->stream_on) - hw->stream_on(dphy, sd); + for (i = 0; i < dphy->csi_info.csi_num; i++) { + if (dphy->csi_info.dphy_vendor[i] == PHY_VENDOR_SAMSUNG) { + dphy->samsung_phy = (struct samsung_mipi_dcphy *)dphy->phy_hw[i]; + if (dphy->samsung_phy && dphy->samsung_phy->stream_on) + dphy->samsung_phy->stream_on(dphy, sd); + } else { + dphy->dphy_hw = (struct csi2_dphy_hw *)dphy->phy_hw[i]; + if (dphy->dphy_hw && dphy->dphy_hw->stream_on) + dphy->dphy_hw->stream_on(dphy, sd); + } } dphy->is_streaming = true; @@ -227,18 +437,21 @@ static int csi2_dphy_s_stream_start(struct v4l2_subdev *sd) static int csi2_dphy_s_stream_stop(struct v4l2_subdev *sd) { struct csi2_dphy *dphy = to_csi2_dphy(sd); - struct csi2_dphy_hw *hw = dphy->dphy_hw; - struct samsung_mipi_dcphy *samsung_phy = dphy->samsung_phy; + int i = 0; - if (!dphy->is_streaming) - return 0; - - if (dphy->drv_data->vendor == PHY_VENDOR_SAMSUNG) { - if (samsung_phy && samsung_phy->stream_off) - samsung_phy->stream_off(dphy, sd); - } else { - if (hw->stream_off) - hw->stream_off(dphy, sd); + for (i = 0; i < dphy->csi_info.csi_num; i++) { + if (dphy->csi_info.dphy_vendor[i] == PHY_VENDOR_SAMSUNG) { + dphy->samsung_phy = (struct samsung_mipi_dcphy *)dphy->phy_hw[i]; + if (dphy->samsung_phy && dphy->samsung_phy->stream_off) + dphy->samsung_phy->stream_off(dphy, sd); + } else { + dphy->dphy_hw = (struct csi2_dphy_hw *)dphy->phy_hw[i]; + if (dphy->dphy_hw && dphy->dphy_hw->stream_off) + dphy->dphy_hw->stream_off(dphy, sd); + } + if (dphy->drv_data->chip_id != CHIP_ID_RK3568 && + dphy->drv_data->chip_id != CHIP_ID_RV1106) + rockchip_csi2_dphy_detach_hw(dphy, dphy->csi_info.csi_idx[i], i); } dphy->is_streaming = false; @@ -249,20 +462,94 @@ static int csi2_dphy_s_stream_stop(struct v4l2_subdev *sd) return 0; } +static int csi2_dphy_enable_clk(struct csi2_dphy *dphy) +{ + struct csi2_dphy_hw *hw = NULL; + struct samsung_mipi_dcphy *samsung_phy = NULL; + int ret; + int i = 0; + + for (i = 0; i < dphy->csi_info.csi_num; i++) { + if (dphy->csi_info.dphy_vendor[i] == PHY_VENDOR_SAMSUNG) { + samsung_phy = (struct samsung_mipi_dcphy *)dphy->phy_hw[i]; + if (samsung_phy) + clk_prepare_enable(samsung_phy->pclk); + } else { + hw = (struct csi2_dphy_hw *)dphy->phy_hw[i]; + if (hw) { + ret = clk_bulk_prepare_enable(hw->num_clks, hw->clks_bulk); + if (ret) { + dev_err(hw->dev, "failed to enable clks\n"); + return ret; + } + } + } + } + return 0; +} + +static void csi2_dphy_disable_clk(struct csi2_dphy *dphy) +{ + struct csi2_dphy_hw *hw = NULL; + struct samsung_mipi_dcphy *samsung_phy = NULL; + int i = 0; + + for (i = 0; i < dphy->csi_info.csi_num; i++) { + if (dphy->csi_info.dphy_vendor[i] == PHY_VENDOR_SAMSUNG) { + samsung_phy = (struct samsung_mipi_dcphy *)dphy->phy_hw[i]; + if (samsung_phy) + clk_disable_unprepare(samsung_phy->pclk); + } else { + hw = (struct csi2_dphy_hw *)dphy->phy_hw[i]; + if (hw) + clk_bulk_disable_unprepare(hw->num_clks, hw->clks_bulk); + } + } +} + static int csi2_dphy_s_stream(struct v4l2_subdev *sd, int on) { struct csi2_dphy *dphy = to_csi2_dphy(sd); int ret = 0; mutex_lock(&dphy->mutex); - if (on) + if (on) { + if (dphy->is_streaming) { + mutex_unlock(&dphy->mutex); + return 0; + } + + ret = csi2_dphy_get_sensor_data_rate(sd); + if (ret < 0) { + mutex_unlock(&dphy->mutex); + return ret; + } + + csi2_dphy_update_sensor_mbus(sd); + ret = csi2_dphy_update_config(sd); + if (ret < 0) { + mutex_unlock(&dphy->mutex); + return ret; + } + + ret = csi2_dphy_enable_clk(dphy); + if (ret) { + mutex_unlock(&dphy->mutex); + return ret; + } ret = csi2_dphy_s_stream_start(sd); - else + } else { + if (!dphy->is_streaming) { + mutex_unlock(&dphy->mutex); + return 0; + } ret = csi2_dphy_s_stream_stop(sd); + csi2_dphy_disable_clk(dphy); + } mutex_unlock(&dphy->mutex); - dev_info(dphy->dev, "%s stream on:%d, dphy%d\n", - __func__, on, dphy->phy_index); + dev_info(dphy->dev, "%s stream on:%d, dphy%d, ret %d\n", + __func__, on, dphy->phy_index, ret); return ret; } @@ -312,15 +599,10 @@ static __maybe_unused int csi2_dphy_runtime_suspend(struct device *dev) struct media_entity *me = dev_get_drvdata(dev); struct v4l2_subdev *sd = media_entity_to_v4l2_subdev(me); struct csi2_dphy *dphy = to_csi2_dphy(sd); - struct csi2_dphy_hw *hw = dphy->dphy_hw; - struct samsung_mipi_dcphy *samsung_phy = dphy->samsung_phy; - if (dphy->drv_data->vendor == PHY_VENDOR_SAMSUNG) { - if (samsung_phy) - clk_disable_unprepare(samsung_phy->pclk); - } else { - if (hw) - clk_bulk_disable_unprepare(hw->num_clks, hw->clks_bulk); + if (dphy->is_streaming) { + csi2_dphy_s_stream(sd, 0); + dphy->is_streaming = false; } return 0; @@ -328,26 +610,6 @@ static __maybe_unused int csi2_dphy_runtime_suspend(struct device *dev) static __maybe_unused int csi2_dphy_runtime_resume(struct device *dev) { - struct media_entity *me = dev_get_drvdata(dev); - struct v4l2_subdev *sd = media_entity_to_v4l2_subdev(me); - struct csi2_dphy *dphy = to_csi2_dphy(sd); - struct csi2_dphy_hw *hw = dphy->dphy_hw; - struct samsung_mipi_dcphy *samsung_phy = dphy->samsung_phy; - int ret; - - if (dphy->drv_data->vendor == PHY_VENDOR_SAMSUNG) { - if (samsung_phy) - clk_prepare_enable(samsung_phy->pclk); - } else { - if (hw) { - ret = clk_bulk_prepare_enable(hw->num_clks, hw->clks_bulk); - if (ret) { - dev_err(hw->dev, "failed to enable clks\n"); - return ret; - } - } - } - return 0; } @@ -384,8 +646,55 @@ static int csi2_dphy_get_selection(struct v4l2_subdev *sd, return v4l2_subdev_call(sensor, pad, get_selection, NULL, sel); } +static long rkcif_csi2_dphy_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg) +{ + struct csi2_dphy *dphy = to_csi2_dphy(sd); + long ret = 0; + + switch (cmd) { + case RKCIF_CMD_SET_CSI_IDX: + if (dphy->drv_data->chip_id != CHIP_ID_RK3568 && + dphy->drv_data->chip_id != CHIP_ID_RV1106) + dphy->csi_info = *((struct rkcif_csi_info *)arg); + break; + default: + ret = -ENOIOCTLCMD; + break; + } + + return ret; +} + +#ifdef CONFIG_COMPAT +static long rkcif_csi2_dphy_compat_ioctl32(struct v4l2_subdev *sd, + unsigned int cmd, unsigned long arg) +{ + void __user *up = compat_ptr(arg); + struct rkcif_csi_info csi_info = {0}; + long ret; + + switch (cmd) { + case RKCIF_CMD_SET_CSI_IDX: + if (copy_from_user(&csi_info, up, sizeof(struct rkcif_csi_info))) + return -EFAULT; + + ret = rkcif_csi2_dphy_ioctl(sd, cmd, &csi_info); + break; + default: + ret = -ENOIOCTLCMD; + break; + } + + return ret; +} +#endif + static const struct v4l2_subdev_core_ops csi2_dphy_core_ops = { .s_power = csi2_dphy_s_power, + .ioctl = rkcif_csi2_dphy_ioctl, +#ifdef CONFIG_COMPAT + .compat_ioctl32 = rkcif_csi2_dphy_compat_ioctl32, +#endif }; static const struct v4l2_subdev_video_ops csi2_dphy_video_ops = { @@ -559,162 +868,32 @@ static int rockchip_csi2dphy_media_init(struct csi2_dphy *dphy) return v4l2_async_register_subdev(&dphy->sd); } -static int rockchip_csi2_dphy_attach_samsung_phy(struct csi2_dphy *dphy) -{ - struct device *dev = dphy->dev; - struct phy *dcphy; - struct samsung_mipi_dcphy *dphy_hw; - int ret = 0; - - dcphy = devm_phy_optional_get(dev, "dcphy"); - if (IS_ERR(dcphy)) { - ret = PTR_ERR(dcphy); - dev_err(dphy->dev, "failed to get mipi dcphy: %d\n", ret); - return ret; - } - - dphy_hw = phy_get_drvdata(dcphy); - dphy_hw->dphy_dev[dphy_hw->dphy_dev_num] = dphy; - dphy_hw->dphy_dev_num++; - dphy->samsung_phy = dphy_hw; - - return 0; -} - -static int rockchip_csi2_dphy_detach_samsung_phy(struct csi2_dphy *dphy) -{ - struct samsung_mipi_dcphy *dphy_hw = dphy->samsung_phy; - struct csi2_dphy *csi2_dphy = NULL; - int i; - - for (i = 0; i < dphy_hw->dphy_dev_num; i++) { - csi2_dphy = dphy_hw->dphy_dev[i]; - if (csi2_dphy && - csi2_dphy->phy_index == dphy->phy_index) { - dphy_hw->dphy_dev[i] = NULL; - dphy_hw->dphy_dev_num--; - break; - } - } - - return 0; -} - -static int rockchip_csi2_dphy_attach_hw(struct csi2_dphy *dphy) -{ - struct platform_device *plat_dev; - struct device *dev = dphy->dev; - struct csi2_dphy_hw *dphy_hw; - struct device_node *np; - enum csi2_dphy_lane_mode target_mode; - int i; - - if (dphy->phy_index % 3 == 0) - target_mode = LANE_MODE_FULL; - else - target_mode = LANE_MODE_SPLIT; - - np = of_parse_phandle(dev->of_node, "rockchip,hw", 0); - if (!np || !of_device_is_available(np)) { - dev_err(dphy->dev, - "failed to get dphy%d hw node\n", dphy->phy_index); - return -ENODEV; - } - - plat_dev = of_find_device_by_node(np); - of_node_put(np); - if (!plat_dev) { - dev_err(dphy->dev, - "failed to get dphy%d hw from node\n", - dphy->phy_index); - return -ENODEV; - } - - dphy_hw = platform_get_drvdata(plat_dev); - if (!dphy_hw) { - dev_err(dphy->dev, - "failed attach dphy%d hw\n", - dphy->phy_index); - return -EINVAL; - } - - if (dphy_hw->lane_mode == LANE_MODE_UNDEF) { - dphy_hw->lane_mode = target_mode; - } else { - struct csi2_dphy *phy = dphy_hw->dphy_dev[0]; - - for (i = 0; i < dphy_hw->dphy_dev_num; i++) { - if (dphy_hw->dphy_dev[i]->lane_mode == dphy_hw->lane_mode) { - phy = dphy_hw->dphy_dev[i]; - break; - } - } - - if (target_mode != dphy_hw->lane_mode) { - dev_err(dphy->dev, - "Err:csi2 dphy hw has been set as %s mode by phy%d, target mode is:%s\n", - dphy_hw->lane_mode == LANE_MODE_FULL ? "full" : "split", - phy->phy_index, - target_mode == LANE_MODE_FULL ? "full" : "split"); - return -ENODEV; - } - } - - dphy_hw->dphy_dev[dphy_hw->dphy_dev_num] = dphy; - dphy_hw->dphy_dev_num++; - dphy->dphy_hw = dphy_hw; - - return 0; -} - -static int rockchip_csi2_dphy_detach_hw(struct csi2_dphy *dphy) -{ - struct csi2_dphy_hw *dphy_hw = dphy->dphy_hw; - struct csi2_dphy *csi2_dphy = NULL; - int i; - - for (i = 0; i < dphy_hw->dphy_dev_num; i++) { - csi2_dphy = dphy_hw->dphy_dev[i]; - if (csi2_dphy && - csi2_dphy->phy_index == dphy->phy_index) { - dphy_hw->dphy_dev[i] = NULL; - dphy_hw->dphy_dev_num--; - break; - } - } - - return 0; -} - static struct dphy_drv_data rk3568_dphy_drv_data = { .dev_name = "csi2dphy", - .vendor = PHY_VENDOR_INNO, + .chip_id = CHIP_ID_RK3568, + .num_inno_phy = 1, + .num_samsung_phy = 0, }; -static struct dphy_drv_data rk3588_dcphy_drv_data = { - .dev_name = "csi2dcphy", - .vendor = PHY_VENDOR_SAMSUNG, -}; - -static struct rkmodule_csi_dphy_param rk3588_dcphy_param = { - .vendor = PHY_VENDOR_SAMSUNG, - .lp_vol_ref = 3, - .lp_hys_sw = {3, 0, 0, 0}, - .lp_escclk_pol_sel = {1, 0, 0, 0}, - .skew_data_cal_clk = {0, 3, 3, 3}, - .clk_hs_term_sel = 2, - .data_hs_term_sel = {2, 2, 2, 2}, - .reserved = {0}, +static struct dphy_drv_data rk3588_dphy_drv_data = { + .dev_name = "csi2dphy", + .chip_id = CHIP_ID_RK3588, + .num_inno_phy = 2, + .num_samsung_phy = 2, }; static struct dphy_drv_data rv1106_dphy_drv_data = { .dev_name = "csi2dphy", - .vendor = PHY_VENDOR_INNO, + .chip_id = CHIP_ID_RV1106, + .num_inno_phy = 1, + .num_samsung_phy = 0, }; static struct dphy_drv_data rk3562_dphy_drv_data = { .dev_name = "csi2dphy", - .vendor = PHY_VENDOR_INNO, + .chip_id = CHIP_ID_RK3562, + .num_inno_phy = 2, + .num_samsung_phy = 0, }; static const struct of_device_id rockchip_csi2_dphy_match_id[] = { @@ -723,8 +902,8 @@ static const struct of_device_id rockchip_csi2_dphy_match_id[] = { .data = &rk3568_dphy_drv_data, }, { - .compatible = "rockchip,rk3588-csi2-dcphy", - .data = &rk3588_dcphy_drv_data, + .compatible = "rockchip,rk3588-csi2-dphy", + .data = &rk3588_dphy_drv_data, }, { .compatible = "rockchip,rv1106-csi2-dphy", @@ -738,6 +917,79 @@ static const struct of_device_id rockchip_csi2_dphy_match_id[] = { }; MODULE_DEVICE_TABLE(of, rockchip_csi2_dphy_match_id); +static int rockchip_csi2_dphy_get_samsung_phy_hw(struct csi2_dphy *dphy) +{ + struct phy *dcphy; + struct device *dev = dphy->dev; + struct samsung_mipi_dcphy *dcphy_hw; + char phy_name[32]; + int i = 0; + int ret = 0; + + for (i = 0; i < dphy->drv_data->num_samsung_phy; i++) { + sprintf(phy_name, "dcphy%d", i); + dcphy = devm_phy_optional_get(dev, phy_name); + if (IS_ERR(dcphy)) { + ret = PTR_ERR(dcphy); + dev_err(dphy->dev, "failed to get mipi dcphy: %d\n", ret); + return ret; + } + dcphy_hw = phy_get_drvdata(dcphy); + dphy->samsung_phy_group[i] = dcphy_hw; + } + return 0; +} + +static int rockchip_csi2_dphy_get_inno_phy_hw(struct csi2_dphy *dphy) +{ + struct platform_device *plat_dev; + struct device *dev = dphy->dev; + struct csi2_dphy_hw *dphy_hw; + struct device_node *np; + int i = 0; + + for (i = 0; i < dphy->drv_data->num_inno_phy; i++) { + np = of_parse_phandle(dev->of_node, "rockchip,hw", i); + if (!np || !of_device_is_available(np)) { + dev_err(dphy->dev, + "failed to get dphy%d hw node\n", dphy->phy_index); + return -ENODEV; + } + plat_dev = of_find_device_by_node(np); + of_node_put(np); + if (!plat_dev) { + dev_err(dphy->dev, + "failed to get dphy%d hw from node\n", + dphy->phy_index); + return -ENODEV; + } + dphy_hw = platform_get_drvdata(plat_dev); + if (!dphy_hw) { + dev_err(dphy->dev, + "failed attach dphy%d hw\n", + dphy->phy_index); + return -EINVAL; + } + dphy->dphy_hw_group[i] = dphy_hw; + } + return 0; +} + +static int rockchip_csi2_dphy_get_hw(struct csi2_dphy *dphy) +{ + int ret = 0; + + if (dphy->drv_data->chip_id == CHIP_ID_RK3588) { + ret = rockchip_csi2_dphy_get_samsung_phy_hw(dphy); + if (ret) + return ret; + ret = rockchip_csi2_dphy_get_inno_phy_hw(dphy); + } else { + ret = rockchip_csi2_dphy_get_inno_phy_hw(dphy); + } + return ret; +} + static int rockchip_csi2_dphy_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; @@ -757,22 +1009,22 @@ static int rockchip_csi2_dphy_probe(struct platform_device *pdev) return -EINVAL; drv_data = of_id->data; csi2dphy->drv_data = drv_data; + csi2dphy->phy_index = of_alias_get_id(dev->of_node, drv_data->dev_name); if (csi2dphy->phy_index < 0 || csi2dphy->phy_index >= PHY_MAX) csi2dphy->phy_index = 0; - if (csi2dphy->drv_data->vendor == PHY_VENDOR_SAMSUNG) { - ret = rockchip_csi2_dphy_attach_samsung_phy(csi2dphy); - csi2dphy->dphy_param = rk3588_dcphy_param; - } else { - ret = rockchip_csi2_dphy_attach_hw(csi2dphy); - } - if (ret) { - dev_err(dev, - "csi2 dphy hw can't be attached, register dphy%d failed!\n", - csi2dphy->phy_index); - return -ENODEV; - } + ret = rockchip_csi2_dphy_get_hw(csi2dphy); + if (ret) + return -EINVAL; + if (csi2dphy->drv_data->chip_id == CHIP_ID_RK3568 || + csi2dphy->drv_data->chip_id == CHIP_ID_RV1106) { + csi2dphy->csi_info.csi_num = 1; + csi2dphy->csi_info.dphy_vendor[0] = PHY_VENDOR_INNO; + rockchip_csi2_dphy_attach_hw(csi2dphy, 0, 0); + } else { + csi2dphy->csi_info.csi_num = 0; + } sd = &csi2dphy->sd; mutex_init(&csi2dphy->mutex); v4l2_subdev_init(sd, &csi2_dphy_subdev_ops); @@ -795,12 +1047,7 @@ static int rockchip_csi2_dphy_probe(struct platform_device *pdev) detach_hw: mutex_destroy(&csi2dphy->mutex); - if (csi2dphy->drv_data->vendor == PHY_VENDOR_SAMSUNG) - rockchip_csi2_dphy_detach_samsung_phy(csi2dphy); - else - rockchip_csi2_dphy_detach_hw(csi2dphy); - - return 0; + return -EINVAL; } static int rockchip_csi2_dphy_remove(struct platform_device *pdev) @@ -808,7 +1055,10 @@ static int rockchip_csi2_dphy_remove(struct platform_device *pdev) struct media_entity *me = platform_get_drvdata(pdev); struct v4l2_subdev *sd = media_entity_to_v4l2_subdev(me); struct csi2_dphy *dphy = to_csi2_dphy(sd); + int i = 0; + for (i = 0; i < dphy->csi_info.csi_num; i++) + rockchip_csi2_dphy_detach_hw(dphy, dphy->csi_info.csi_idx[i], i); media_entity_cleanup(&sd->entity); pm_runtime_disable(&pdev->dev); diff --git a/drivers/phy/rockchip/phy-rockchip-samsung-dcphy.c b/drivers/phy/rockchip/phy-rockchip-samsung-dcphy.c index 48b570d5a4a7..125e58d83dba 100644 --- a/drivers/phy/rockchip/phy-rockchip-samsung-dcphy.c +++ b/drivers/phy/rockchip/phy-rockchip-samsung-dcphy.c @@ -1269,9 +1269,9 @@ static const struct hsfreq_range samsung_cphy_rx_hsfreq_ranges[] = { { 500, 0x102}, { 990, 0x002}, { 2500, 0x001}, }; -static void samsung_mipi_dcphy_bias_block_enable(struct samsung_mipi_dcphy *samsung) +static void samsung_mipi_dcphy_bias_block_enable(struct samsung_mipi_dcphy *samsung, + struct csi2_dphy *csi_dphy) { - struct csi2_dphy *csi_dphy = samsung->dphy_dev[0]; u32 bias_con2 = 0x3223; if (csi_dphy && @@ -1701,7 +1701,7 @@ static void samsung_mipi_dphy_power_on(struct samsung_mipi_dcphy *samsung) { reset_control_assert(samsung->m_phy_rst); - samsung_mipi_dcphy_bias_block_enable(samsung); + samsung_mipi_dcphy_bias_block_enable(samsung, NULL); samsung_mipi_dcphy_pll_configure(samsung); samsung_mipi_dphy_clk_lane_timing_init(samsung); samsung_mipi_dphy_data_lane_timing_init(samsung); @@ -1721,7 +1721,7 @@ static void samsung_mipi_cphy_power_on(struct samsung_mipi_dcphy *samsung) regmap_write(samsung->grf_regmap, MIPI_DCPHY_GRF_CON0, M_CPHY_MODE); reset_control_assert(samsung->m_phy_rst); - samsung_mipi_dcphy_bias_block_enable(samsung); + samsung_mipi_dcphy_bias_block_enable(samsung, NULL); samsung_mipi_dcphy_hs_vreg_amp_configure(samsung); samsung_mipi_dcphy_pll_configure(samsung); samsung_mipi_cphy_timing_init(samsung); @@ -2207,7 +2207,7 @@ static int samsung_dcphy_rx_stream_on(struct csi2_dphy *dphy, if (samsung->s_phy_rst) reset_control_assert(samsung->s_phy_rst); - samsung_mipi_dcphy_bias_block_enable(samsung); + samsung_mipi_dcphy_bias_block_enable(samsung, dphy); ret = samsung_dcphy_rx_config_common(dphy, sensor); if (ret) goto out_streamon; From a8c5673b5b77c0639d6a4cefca6f7e9aeff815cc Mon Sep 17 00:00:00 2001 From: Zefa Chen Date: Wed, 14 Sep 2022 15:15:03 +0800 Subject: [PATCH 2/3] media: rockchip: vicap support combine two mipi to one dev Signed-off-by: Zefa Chen Change-Id: Iba3e83d0bc1433458d56c2542c3224ffee127b90 --- drivers/media/platform/rockchip/cif/capture.c | 679 +++++++++++++----- drivers/media/platform/rockchip/cif/dev.c | 11 +- drivers/media/platform/rockchip/cif/dev.h | 2 + drivers/media/platform/rockchip/cif/hw.c | 2 + .../media/platform/rockchip/cif/mipi-csi2.c | 403 ++++++++--- .../media/platform/rockchip/cif/mipi-csi2.h | 35 +- .../media/platform/rockchip/cif/subdev-itf.c | 27 +- drivers/media/platform/rockchip/cif/version.h | 2 + 8 files changed, 882 insertions(+), 279 deletions(-) diff --git a/drivers/media/platform/rockchip/cif/capture.c b/drivers/media/platform/rockchip/cif/capture.c index ee29771164ca..2b76a5f17c0e 100644 --- a/drivers/media/platform/rockchip/cif/capture.c +++ b/drivers/media/platform/rockchip/cif/capture.c @@ -852,6 +852,7 @@ cif_input_fmt *get_input_fmt(struct v4l2_subdev *sd, struct v4l2_rect *rect, { struct v4l2_subdev_format fmt; struct rkmodule_channel_info ch_info = {0}; + struct rkmodule_capture_info capture_info; int ret; u32 i; @@ -909,7 +910,12 @@ cif_input_fmt *get_input_fmt(struct v4l2_subdev *sd, struct v4l2_rect *rect, rect->top = 0; rect->width = fmt.format.width; rect->height = fmt.format.height; - + ret = v4l2_subdev_call(sd, + core, ioctl, + RKMODULE_GET_CAPTURE_MODE, + &capture_info); + if (!ret) + csi_info->capture_info = capture_info; for (i = 0; i < ARRAY_SIZE(in_fmts); i++) if (fmt.format.code == in_fmts[i].mbus_code && fmt.format.field == in_fmts[i].field) @@ -1807,14 +1813,51 @@ RDBK_TOISP_UNMATCH: spin_unlock_irqrestore(&dev->hdr_lock, flags); } +static void rkcif_write_buff_addr_multi_dev_combine(struct rkcif_stream *stream, + u32 frm_addr_y, u32 frm_addr_uv, + u32 buff_addr_y, u32 buff_addr_cbcr, + bool is_dummy_buf) +{ + struct rkcif_device *dev = stream->cifdev; + struct rkmodule_capture_info *capture_info = &dev->channels[stream->id].capture_info; + u32 addr_y, addr_cbcr; + int addr_offset = 0; + int i = 0; + int tmp_host_index = dev->csi_host_idx; + + for (i = 0; i < capture_info->multi_dev.dev_num; i++) { + if (is_dummy_buf) { + addr_y = buff_addr_y; + } else { + addr_offset = dev->channels[stream->id].left_virtual_width; + addr_y = buff_addr_y + addr_offset * i; + } + dev->csi_host_idx = capture_info->multi_dev.dev_idx[i]; + rkcif_write_register(dev, frm_addr_y, addr_y); + if (stream->cif_fmt_out->fmt_type != CIF_FMT_TYPE_RAW && + frm_addr_uv && buff_addr_cbcr) { + if (is_dummy_buf) { + addr_cbcr = buff_addr_cbcr; + } else { + addr_offset = dev->channels[stream->id].left_virtual_width; + addr_cbcr = buff_addr_cbcr + addr_offset * i; + } + rkcif_write_register(dev, frm_addr_uv, addr_cbcr); + } + } + dev->csi_host_idx = tmp_host_index; +} + static void rkcif_assign_new_buffer_init_toisp(struct rkcif_stream *stream, int channel_id) { struct rkcif_device *dev = stream->cifdev; struct rkcif_rx_buffer *rx_buf; struct v4l2_mbus_config *mbus_cfg = &dev->active_sensor->mbus; + struct rkmodule_capture_info *capture_info = &dev->channels[channel_id].capture_info; u32 frm0_addr_y; u32 frm1_addr_y; + u32 buff_addr_y; unsigned long flags; if (mbus_cfg->type == V4L2_MBUS_CSI2_DPHY || @@ -1841,9 +1884,15 @@ static void rkcif_assign_new_buffer_init_toisp(struct rkcif_stream *stream, } } - if (stream->curr_buf_toisp) - rkcif_write_register(dev, frm0_addr_y, - stream->curr_buf_toisp->dummy.dma_addr); + if (stream->curr_buf_toisp) { + buff_addr_y = stream->curr_buf_toisp->dummy.dma_addr; + if (capture_info->mode == RKMODULE_MULTI_DEV_COMBINE_ONE) { + rkcif_write_buff_addr_multi_dev_combine(stream, frm0_addr_y, 0, + buff_addr_y, 0, false); + } else { + rkcif_write_register(dev, frm0_addr_y, buff_addr_y); + } + } if (!stream->next_buf_toisp) { if (!list_empty(&stream->rx_buf_head)) { @@ -1860,9 +1909,15 @@ static void rkcif_assign_new_buffer_init_toisp(struct rkcif_stream *stream, } } - if (stream->next_buf_toisp) - rkcif_write_register(dev, frm1_addr_y, - stream->next_buf_toisp->dummy.dma_addr); + if (stream->next_buf_toisp) { + buff_addr_y = stream->next_buf_toisp->dummy.dma_addr; + if (capture_info->mode == RKMODULE_MULTI_DEV_COMBINE_ONE) { + rkcif_write_buff_addr_multi_dev_combine(stream, frm1_addr_y, 0, + buff_addr_y, 0, false); + } else { + rkcif_write_register(dev, frm1_addr_y, buff_addr_y); + } + } spin_unlock_irqrestore(&stream->vbq_lock, flags); stream->buf_owner = RKCIF_DMAEN_BY_ISP; @@ -1873,10 +1928,11 @@ static int rkcif_assign_new_buffer_update_toisp(struct rkcif_stream *stream, { struct rkcif_device *dev = stream->cifdev; struct v4l2_mbus_config *mbus_cfg = &dev->active_sensor->mbus; + struct rkmodule_capture_info *capture_info = &dev->channels[channel_id].capture_info; struct rkcif_rx_buffer *buffer = NULL; struct rkcif_rx_buffer *active_buf = NULL; struct sditf_priv *priv = dev->sditf[0]; - u32 frm_addr_y; + u32 frm_addr_y, buff_addr_y; unsigned long flags; if (mbus_cfg->type == V4L2_MBUS_CSI2_DPHY || @@ -2021,8 +2077,13 @@ static int rkcif_assign_new_buffer_update_toisp(struct rkcif_stream *stream, out_get_buf: stream->frame_phase_cache = stream->frame_phase; if (buffer) { - rkcif_write_register(dev, frm_addr_y, - buffer->dummy.dma_addr); + buff_addr_y = buffer->dummy.dma_addr; + if (capture_info->mode == RKMODULE_MULTI_DEV_COMBINE_ONE) { + rkcif_write_buff_addr_multi_dev_combine(stream, frm_addr_y, 0, + buff_addr_y, 0, false); + } else { + rkcif_write_register(dev, frm_addr_y, buff_addr_y); + } if (dev->rdbk_debug > 1 && stream->frame_idx < 15) v4l2_info(&dev->v4l2_dev, @@ -2032,8 +2093,13 @@ out_get_buf: frm_addr_y, (u32)buffer->dummy.dma_addr); } else if (dev->hw_dev->dummy_buf.vaddr && priv && priv->mode.rdbk_mode == RKISP_VICAP_RDBK_AUTO) { - rkcif_write_register(dev, frm_addr_y, - dev->hw_dev->dummy_buf.dma_addr); + buff_addr_y = dev->hw_dev->dummy_buf.dma_addr; + if (capture_info->mode == RKMODULE_MULTI_DEV_COMBINE_ONE) { + rkcif_write_buff_addr_multi_dev_combine(stream, frm_addr_y, 0, + buff_addr_y, 0, true); + } else { + rkcif_write_register(dev, frm_addr_y, buff_addr_y); + } } spin_unlock_irqrestore(&stream->vbq_lock, flags); return 0; @@ -2056,8 +2122,9 @@ void rkcif_assign_check_buffer_update_toisp(struct rkcif_stream *stream) struct rkcif_device *dev = stream->cifdev; struct v4l2_mbus_config *mbus_cfg = &dev->active_sensor->mbus; struct rkcif_rx_buffer *buffer = NULL; + struct rkmodule_capture_info *capture_info = &dev->channels[stream->id].capture_info; struct rkcif_rx_buffer *active_buf = NULL; - u32 frm_addr_y; + u32 frm_addr_y, buff_addr_y; u32 vblank = 0; u32 vblank_ns = 0; u64 cur_time = 0; @@ -2120,8 +2187,15 @@ void rkcif_assign_check_buffer_update_toisp(struct rkcif_stream *stream) if (buffer) { list_del(&buffer->list); stream->curr_buf_toisp = buffer; - rkcif_write_register(dev, frm_addr_y, - stream->curr_buf_toisp->dummy.dma_addr); + buff_addr_y = stream->curr_buf_toisp->dummy.dma_addr; + if (capture_info->mode == RKMODULE_MULTI_DEV_COMBINE_ONE) { + rkcif_write_buff_addr_multi_dev_combine(stream, + frm_addr_y, 0, + buff_addr_y, 0, + false); + } else { + rkcif_write_register(dev, frm_addr_y, buff_addr_y); + } if (dev->rdbk_debug > 1 && stream->frame_idx < 15) v4l2_info(&dev->v4l2_dev, @@ -2137,8 +2211,15 @@ void rkcif_assign_check_buffer_update_toisp(struct rkcif_stream *stream) if (buffer) { list_del(&buffer->list); stream->next_buf_toisp = buffer; - rkcif_write_register(dev, frm_addr_y, - stream->next_buf_toisp->dummy.dma_addr); + buff_addr_y = stream->next_buf_toisp->dummy.dma_addr; + if (capture_info->mode == RKMODULE_MULTI_DEV_COMBINE_ONE) { + rkcif_write_buff_addr_multi_dev_combine(stream, + frm_addr_y, 0, + buff_addr_y, 0, + false); + } else { + rkcif_write_register(dev, frm_addr_y, buff_addr_y); + } if (dev->rdbk_debug > 1 && stream->frame_idx < 15) v4l2_info(&dev->v4l2_dev, @@ -2186,8 +2267,13 @@ void rkcif_assign_check_buffer_update_toisp(struct rkcif_stream *stream) stream->next_buf_toisp = stream->curr_buf_toisp; else stream->curr_buf_toisp = stream->next_buf_toisp; - rkcif_write_register(dev, frm_addr_y, - stream->curr_buf_toisp->dummy.dma_addr); + buff_addr_y = stream->curr_buf_toisp->dummy.dma_addr; + if (capture_info->mode == RKMODULE_MULTI_DEV_COMBINE_ONE) { + rkcif_write_buff_addr_multi_dev_combine(stream, frm_addr_y, 0, + buff_addr_y, 0, false); + } else { + rkcif_write_register(dev, frm_addr_y, buff_addr_y); + } } } @@ -2198,6 +2284,7 @@ static void rkcif_assign_new_buffer_init(struct rkcif_stream *stream, struct v4l2_mbus_config *mbus_cfg = &dev->active_sensor->mbus; u32 frm0_addr_y, frm0_addr_uv; u32 frm1_addr_y, frm1_addr_uv; + u32 buff_addr_y, buff_addr_cbcr; unsigned long flags; struct rkcif_dummy_buffer *dummy_buf = &dev->hw_dev->dummy_buf; struct csi_channel_info *channel = &dev->channels[channel_id]; @@ -2228,16 +2315,38 @@ static void rkcif_assign_new_buffer_init(struct rkcif_stream *stream, } if (stream->curr_buf) { - rkcif_write_register(dev, frm0_addr_y, - stream->curr_buf->buff_addr[RKCIF_PLANE_Y]); - if (stream->cif_fmt_out->fmt_type != CIF_FMT_TYPE_RAW) - rkcif_write_register(dev, frm0_addr_uv, - stream->curr_buf->buff_addr[RKCIF_PLANE_CBCR]); + buff_addr_y = stream->curr_buf->buff_addr[RKCIF_PLANE_Y]; + buff_addr_cbcr = stream->curr_buf->buff_addr[RKCIF_PLANE_CBCR]; + if (channel->capture_info.mode == RKMODULE_MULTI_DEV_COMBINE_ONE) { + rkcif_write_buff_addr_multi_dev_combine(stream, + frm0_addr_y, + frm0_addr_uv, + buff_addr_y, + buff_addr_cbcr, + false); + } else { + rkcif_write_register(dev, frm0_addr_y, + stream->curr_buf->buff_addr[RKCIF_PLANE_Y]); + if (stream->cif_fmt_out->fmt_type != CIF_FMT_TYPE_RAW) + rkcif_write_register(dev, frm0_addr_uv, + stream->curr_buf->buff_addr[RKCIF_PLANE_CBCR]); + } } else { if (dummy_buf->vaddr) { - rkcif_write_register(dev, frm0_addr_y, dummy_buf->dma_addr); - if (stream->cif_fmt_out->fmt_type != CIF_FMT_TYPE_RAW) - rkcif_write_register(dev, frm0_addr_uv, dummy_buf->dma_addr); + buff_addr_y = dummy_buf->dma_addr; + buff_addr_cbcr = dummy_buf->dma_addr; + if (channel->capture_info.mode == RKMODULE_MULTI_DEV_COMBINE_ONE) { + rkcif_write_buff_addr_multi_dev_combine(stream, + frm0_addr_y, + frm0_addr_uv, + buff_addr_y, + buff_addr_cbcr, + true); + } else { + rkcif_write_register(dev, frm0_addr_y, buff_addr_y); + if (stream->cif_fmt_out->fmt_type != CIF_FMT_TYPE_RAW) + rkcif_write_register(dev, frm0_addr_uv, buff_addr_cbcr); + } } else { if (stream->lack_buf_cnt < 2) stream->lack_buf_cnt++; @@ -2247,11 +2356,22 @@ static void rkcif_assign_new_buffer_init(struct rkcif_stream *stream, if (stream->cif_fmt_in->field == V4L2_FIELD_INTERLACED) { stream->next_buf = stream->curr_buf; if (stream->next_buf) { - rkcif_write_register(dev, frm1_addr_y, - stream->next_buf->buff_addr[RKCIF_PLANE_Y] + (channel->virtual_width / 2)); - if (stream->cif_fmt_out->fmt_type != CIF_FMT_TYPE_RAW) - rkcif_write_register(dev, frm1_addr_uv, - stream->next_buf->buff_addr[RKCIF_PLANE_CBCR] + (channel->virtual_width / 2)); + buff_addr_y = stream->next_buf->buff_addr[RKCIF_PLANE_Y]; + buff_addr_cbcr = stream->next_buf->buff_addr[RKCIF_PLANE_CBCR]; + if (channel->capture_info.mode == RKMODULE_MULTI_DEV_COMBINE_ONE) { + rkcif_write_buff_addr_multi_dev_combine(stream, + frm1_addr_y, + frm1_addr_uv, + buff_addr_y, + buff_addr_cbcr, + false); + } else { + rkcif_write_register(dev, frm1_addr_y, + buff_addr_y + (channel->virtual_width / 2)); + if (stream->cif_fmt_out->fmt_type != CIF_FMT_TYPE_RAW) + rkcif_write_register(dev, frm1_addr_uv, + buff_addr_cbcr + (channel->virtual_width / 2)); + } } } else { if (!stream->next_buf) { @@ -2262,28 +2382,41 @@ static void rkcif_assign_new_buffer_init(struct rkcif_stream *stream, } } - if (stream->next_buf) { - rkcif_write_register(dev, frm1_addr_y, - stream->next_buf->buff_addr[RKCIF_PLANE_Y]); - if (stream->cif_fmt_out->fmt_type != CIF_FMT_TYPE_RAW) - rkcif_write_register(dev, frm1_addr_uv, - stream->next_buf->buff_addr[RKCIF_PLANE_CBCR]); - } else { - if (dummy_buf->vaddr) { + if (!stream->next_buf && dummy_buf->vaddr) { + buff_addr_y = dummy_buf->dma_addr; + buff_addr_cbcr = dummy_buf->dma_addr; + if (channel->capture_info.mode == RKMODULE_MULTI_DEV_COMBINE_ONE) { + rkcif_write_buff_addr_multi_dev_combine(stream, + frm1_addr_y, + frm1_addr_uv, + buff_addr_y, + buff_addr_cbcr, + true); + } else { rkcif_write_register(dev, frm1_addr_y, dummy_buf->dma_addr); if (stream->cif_fmt_out->fmt_type != CIF_FMT_TYPE_RAW) rkcif_write_register(dev, frm1_addr_uv, dummy_buf->dma_addr); + } + + } else if (!stream->next_buf && stream->curr_buf) { + stream->next_buf = stream->curr_buf; + if (stream->lack_buf_cnt < 2) + stream->lack_buf_cnt++; + } + if (stream->next_buf) { + buff_addr_y = stream->next_buf->buff_addr[RKCIF_PLANE_Y]; + buff_addr_cbcr = stream->next_buf->buff_addr[RKCIF_PLANE_CBCR]; + if (channel->capture_info.mode == RKMODULE_MULTI_DEV_COMBINE_ONE) { + rkcif_write_buff_addr_multi_dev_combine(stream, + frm1_addr_y, + frm1_addr_uv, + buff_addr_y, + buff_addr_cbcr, + false); } else { - if (stream->curr_buf) { - stream->next_buf = stream->curr_buf; - rkcif_write_register(dev, frm1_addr_y, - stream->next_buf->buff_addr[RKCIF_PLANE_Y]); - if (stream->cif_fmt_out->fmt_type != CIF_FMT_TYPE_RAW) - rkcif_write_register(dev, frm1_addr_uv, - stream->next_buf->buff_addr[RKCIF_PLANE_CBCR]); - } - if (stream->lack_buf_cnt < 2) - stream->lack_buf_cnt++; + rkcif_write_register(dev, frm1_addr_y, buff_addr_y); + if (stream->cif_fmt_out->fmt_type != CIF_FMT_TYPE_RAW) + rkcif_write_register(dev, frm1_addr_uv, buff_addr_cbcr); } } } @@ -2331,6 +2464,7 @@ static int rkcif_assign_new_buffer_update(struct rkcif_stream *stream, struct rkisp_rx_buf *dbufs = NULL; struct dma_buf *dbuf = NULL; int ret = 0; + u32 buff_addr_y, buff_addr_cbcr; unsigned long flags; if (mbus_cfg->type == V4L2_MBUS_CSI2_DPHY || @@ -2443,19 +2577,37 @@ static int rkcif_assign_new_buffer_update(struct rkcif_stream *stream, stream->frame_phase_cache = stream->frame_phase; if (buffer) { + buff_addr_y = buffer->buff_addr[RKCIF_PLANE_Y]; + buff_addr_cbcr = buffer->buff_addr[RKCIF_PLANE_CBCR]; if (stream->cif_fmt_in->field == V4L2_FIELD_INTERLACED && stream->frame_phase == CIF_CSI_FRAME1_READY) { - rkcif_write_register(dev, frm_addr_y, - buffer->buff_addr[RKCIF_PLANE_Y] + (channel->virtual_width / 2)); - if (stream->cif_fmt_out->fmt_type != CIF_FMT_TYPE_RAW) - rkcif_write_register(dev, frm_addr_uv, - buffer->buff_addr[RKCIF_PLANE_CBCR] + (channel->virtual_width / 2)); + if (channel->capture_info.mode == RKMODULE_MULTI_DEV_COMBINE_ONE) { + rkcif_write_buff_addr_multi_dev_combine(stream, + frm_addr_y, + frm_addr_uv, + buff_addr_y, + buff_addr_cbcr, + false); + } else { + rkcif_write_register(dev, frm_addr_y, + buff_addr_y + (channel->virtual_width / 2)); + if (stream->cif_fmt_out->fmt_type != CIF_FMT_TYPE_RAW) + rkcif_write_register(dev, frm_addr_uv, + buff_addr_cbcr + (channel->virtual_width / 2)); + } } else { - rkcif_write_register(dev, frm_addr_y, - buffer->buff_addr[RKCIF_PLANE_Y]); - if (stream->cif_fmt_out->fmt_type != CIF_FMT_TYPE_RAW) - rkcif_write_register(dev, frm_addr_uv, - buffer->buff_addr[RKCIF_PLANE_CBCR]); + if (channel->capture_info.mode == RKMODULE_MULTI_DEV_COMBINE_ONE) { + rkcif_write_buff_addr_multi_dev_combine(stream, + frm_addr_y, + frm_addr_uv, + buff_addr_y, + buff_addr_cbcr, + false); + } else { + rkcif_write_register(dev, frm_addr_y, buff_addr_y); + if (stream->cif_fmt_out->fmt_type != CIF_FMT_TYPE_RAW) + rkcif_write_register(dev, frm_addr_uv, buff_addr_cbcr); + } } if (stream->dma_en & RKCIF_DMAEN_BY_ISP) { if (stream->buf_replace_cnt < 2) @@ -2478,8 +2630,13 @@ static int rkcif_assign_new_buffer_update(struct rkcif_stream *stream, } } else { if (stream->dma_en & RKCIF_DMAEN_BY_ISP) { - rkcif_write_register(dev, frm_addr_y, - stream->curr_buf_toisp->dummy.dma_addr); + buff_addr_y = stream->curr_buf_toisp->dummy.dma_addr; + if (channel->capture_info.mode == RKMODULE_MULTI_DEV_COMBINE_ONE) + rkcif_write_buff_addr_multi_dev_combine(stream, + frm_addr_y, 0, + buff_addr_y, 0, false); + else + rkcif_write_register(dev, frm_addr_y, buff_addr_y); if (stream->frame_phase == CIF_CSI_FRAME0_READY && stream->next_buf) dbuf = stream->next_buf->dbuf; @@ -2505,11 +2662,24 @@ static int rkcif_assign_new_buffer_update(struct rkcif_stream *stream, stream->buf_replace_cnt--; } } else if (dummy_buf->vaddr) { - rkcif_write_register(dev, frm_addr_y, dummy_buf->dma_addr); - if (stream->cif_fmt_out->fmt_type != CIF_FMT_TYPE_RAW) - rkcif_write_register(dev, frm_addr_uv, dummy_buf->dma_addr); + + if (channel->capture_info.mode == RKMODULE_MULTI_DEV_COMBINE_ONE) { + buff_addr_y = dummy_buf->dma_addr; + buff_addr_cbcr = dummy_buf->dma_addr; + rkcif_write_buff_addr_multi_dev_combine(stream, + frm_addr_y, + frm_addr_uv, + buff_addr_y, + buff_addr_cbcr, + true); + } else { + rkcif_write_register(dev, frm_addr_y, dummy_buf->dma_addr); + if (stream->cif_fmt_out->fmt_type != CIF_FMT_TYPE_RAW) + rkcif_write_register(dev, frm_addr_uv, dummy_buf->dma_addr); + } dev->err_state |= (RKCIF_ERR_ID0_NOT_BUF << stream->id); dev->irq_stats.not_active_buf_cnt[stream->id]++; + } else { ret = -EINVAL; stream->curr_buf = NULL; @@ -2523,8 +2693,13 @@ static int rkcif_assign_new_buffer_update(struct rkcif_stream *stream, stop_dma: if (stream->buf_replace_cnt) { spin_lock_irqsave(&stream->vbq_lock, flags); - rkcif_write_register(dev, frm_addr_y, - stream->curr_buf_toisp->dummy.dma_addr); + buff_addr_y = stream->curr_buf_toisp->dummy.dma_addr; + if (channel->capture_info.mode == RKMODULE_MULTI_DEV_COMBINE_ONE) + rkcif_write_buff_addr_multi_dev_combine(stream, + frm_addr_y, 0, + buff_addr_y, 0, false); + else + rkcif_write_register(dev, frm_addr_y, buff_addr_y); if (stream->frame_phase == CIF_CSI_FRAME0_READY && stream->next_buf) dbuf = stream->next_buf->dbuf; @@ -2620,8 +2795,10 @@ static int rkcif_update_new_buffer_wake_up_mode(struct rkcif_stream *stream) struct rkcif_device *dev = stream->cifdev; struct rkcif_dummy_buffer *dummy_buf = &dev->hw_dev->dummy_buf; struct v4l2_mbus_config *mbus_cfg = &dev->active_sensor->mbus; + struct rkmodule_capture_info *capture_info = &dev->channels[stream->id].capture_info; struct rkcif_buffer *buffer = NULL; u32 frm_addr_y, frm_addr_uv; + u32 buff_addr_y, buff_addr_cbcr; int channel_id = stream->id; int ret = 0; unsigned long flags; @@ -2652,16 +2829,35 @@ static int rkcif_update_new_buffer_wake_up_mode(struct rkcif_stream *stream) } spin_unlock_irqrestore(&stream->vbq_lock, flags); if (buffer) { - rkcif_write_register(dev, frm_addr_y, - buffer->buff_addr[RKCIF_PLANE_Y]); - if (stream->cif_fmt_out->fmt_type != CIF_FMT_TYPE_RAW) - rkcif_write_register(dev, frm_addr_uv, - buffer->buff_addr[RKCIF_PLANE_CBCR]); + buff_addr_y = buffer->buff_addr[RKCIF_PLANE_Y]; + buff_addr_cbcr = buffer->buff_addr[RKCIF_PLANE_CBCR]; + if (capture_info->mode == RKMODULE_MULTI_DEV_COMBINE_ONE) { + rkcif_write_buff_addr_multi_dev_combine(stream, frm_addr_y, + frm_addr_uv, + buff_addr_y, + buff_addr_cbcr, + false); + } else { + rkcif_write_register(dev, frm_addr_y, buff_addr_y); + if (stream->cif_fmt_out->fmt_type != CIF_FMT_TYPE_RAW) + rkcif_write_register(dev, frm_addr_uv, buff_addr_cbcr); + } } else { if (dummy_buf->vaddr) { - rkcif_write_register(dev, frm_addr_y, dummy_buf->dma_addr); - if (stream->cif_fmt_out->fmt_type != CIF_FMT_TYPE_RAW) - rkcif_write_register(dev, frm_addr_uv, dummy_buf->dma_addr); + buff_addr_y = dummy_buf->dma_addr; + buff_addr_cbcr = dummy_buf->dma_addr; + if (capture_info->mode == RKMODULE_MULTI_DEV_COMBINE_ONE) { + rkcif_write_buff_addr_multi_dev_combine(stream, + frm_addr_y, + frm_addr_uv, + buff_addr_y, + buff_addr_cbcr, + true); + } else { + rkcif_write_register(dev, frm_addr_y, buff_addr_y); + if (stream->cif_fmt_out->fmt_type != CIF_FMT_TYPE_RAW) + rkcif_write_register(dev, frm_addr_uv, buff_addr_cbcr); + } } else { if (dev->chip_id < CHIP_RK3588_CIF) ret = -EINVAL; @@ -3196,6 +3392,7 @@ static int rkcif_csi_channel_init(struct rkcif_stream *stream, struct csi_channel_info *channel) { struct rkcif_device *dev = stream->cifdev; + struct sditf_priv *priv = dev->sditf[0]; const struct cif_output_fmt *fmt; u32 fourcc; int vc = dev->channels[stream->id].vc; @@ -3220,7 +3417,7 @@ static int rkcif_csi_channel_init(struct rkcif_stream *stream, channel->crop_st_x = stream->crop[CROP_SRC_ACT].left; channel->crop_st_y = stream->crop[CROP_SRC_ACT].top; - if (dev->sditf_cnt > 1 && dev->sditf_cnt <= RKCIF_MAX_SDITF) + if (priv && priv->is_combine_mode && dev->sditf_cnt <= RKCIF_MAX_SDITF) channel->crop_st_y *= dev->sditf_cnt; channel->width = stream->crop[CROP_SRC_ACT].width; channel->height = stream->crop[CROP_SRC_ACT].height; @@ -3230,7 +3427,7 @@ static int rkcif_csi_channel_init(struct rkcif_stream *stream, channel->crop_en = 0; } - if (dev->sditf_cnt > 1 && dev->sditf_cnt <= RKCIF_MAX_SDITF) + if (priv && priv->is_combine_mode && dev->sditf_cnt <= RKCIF_MAX_SDITF) channel->height *= dev->sditf_cnt; fmt = rkcif_find_output_fmt(stream, stream->pixm.pixelformat); @@ -3240,6 +3437,8 @@ static int rkcif_csi_channel_init(struct rkcif_stream *stream, return -EINVAL; } + if (channel->capture_info.mode == RKMODULE_MULTI_DEV_COMBINE_ONE) + channel->width /= channel->capture_info.multi_dev.dev_num; /* * for mipi or lvds, when enable compact, the virtual width of raw10/raw12 * needs aligned with :ALIGN(bits_per_pixel * width / 8, 8), if enable 16bit mode @@ -3249,9 +3448,19 @@ static int rkcif_csi_channel_init(struct rkcif_stream *stream, if (fmt->fmt_type == CIF_FMT_TYPE_RAW && stream->is_compact && fmt->csi_fmt_val != CSI_WRDDR_TYPE_RGB888 && fmt->csi_fmt_val != CSI_WRDDR_TYPE_RGB565) { - channel->virtual_width = ALIGN(channel->width * fmt->raw_bpp / 8, 256); + if (channel->capture_info.mode == RKMODULE_MULTI_DEV_COMBINE_ONE) { + channel->virtual_width = ALIGN(channel->width * 2 * fmt->raw_bpp / 8, 256); + channel->left_virtual_width = channel->width * fmt->raw_bpp / 8; + } else { + channel->virtual_width = ALIGN(channel->width * fmt->raw_bpp / 8, 256); + } } else { - channel->virtual_width = ALIGN(channel->width * fmt->bpp[0] / 8, 8); + if (channel->capture_info.mode == RKMODULE_MULTI_DEV_COMBINE_ONE) { + channel->virtual_width = ALIGN(channel->width * 2 * fmt->bpp[0] / 8, 8); + channel->left_virtual_width = ALIGN(channel->width * fmt->bpp[0] / 8, 8); + } else { + channel->virtual_width = ALIGN(channel->width * fmt->bpp[0] / 8, 8); + } } if (channel->fmt_val == CSI_WRDDR_TYPE_RGB888 || channel->fmt_val == CSI_WRDDR_TYPE_RGB565) @@ -3270,6 +3479,8 @@ static int rkcif_csi_channel_init(struct rkcif_stream *stream, channel->width *= 2; } channel->virtual_width *= 2; + if (channel->capture_info.mode == RKMODULE_MULTI_DEV_COMBINE_ONE) + channel->left_virtual_width *= 2; } if (stream->cif_fmt_in->field == V4L2_FIELD_INTERLACED) { channel->virtual_width *= 2; @@ -3618,15 +3829,18 @@ static void rkcif_modify_frame_skip_config(struct rkcif_stream *stream) /*config reg for rk3588*/ static int rkcif_csi_channel_set_v1(struct rkcif_stream *stream, - struct csi_channel_info *channel, - enum v4l2_mbus_type mbus_type, unsigned int mode) + struct csi_channel_info *channel, + enum v4l2_mbus_type mbus_type, unsigned int mode, + int index) { unsigned int val = 0x0; struct rkcif_device *dev = stream->cifdev; struct rkcif_stream *detect_stream = &dev->stream[0]; struct sditf_priv *priv = dev->sditf[0]; + struct rkmodule_capture_info *capture_info = &channel->capture_info; unsigned int wait_line = 0x3fff; unsigned int dma_en = 0; + int offset = 0; if (channel->id >= 4) return -EINVAL; @@ -3642,21 +3856,28 @@ static int rkcif_csi_channel_set_v1(struct rkcif_stream *stream, CSI_DMA_END_INTSTAT(channel->id) | CSI_LINE_INTSTAT_V1(channel->id))); - rkcif_write_register_or(dev, CIF_REG_MIPI_LVDS_INTEN, - CSI_START_INTEN(channel->id)); + if (!(capture_info->mode == RKMODULE_MULTI_DEV_COMBINE_ONE && + index < capture_info->multi_dev.dev_num - 1)) { - if (priv && priv->mode.rdbk_mode && detect_stream->is_line_wake_up) { rkcif_write_register_or(dev, CIF_REG_MIPI_LVDS_INTEN, - CSI_LINE_INTEN_RK3588(channel->id)); - wait_line = dev->wait_line; - } - rkcif_write_register(dev, CIF_REG_MIPI_LVDS_LINE_INT_NUM_ID0_1, - wait_line << 16 | wait_line); - rkcif_write_register(dev, CIF_REG_MIPI_LVDS_LINE_INT_NUM_ID2_3, - wait_line << 16 | wait_line); + CSI_START_INTEN(channel->id)); - rkcif_write_register_or(dev, CIF_REG_MIPI_LVDS_INTEN, - CSI_DMA_END_INTEN(channel->id)); + if (priv && priv->mode.rdbk_mode && detect_stream->is_line_wake_up) { + rkcif_write_register_or(dev, CIF_REG_MIPI_LVDS_INTEN, + CSI_LINE_INTEN_RK3588(channel->id)); + wait_line = dev->wait_line; + } + rkcif_write_register(dev, CIF_REG_MIPI_LVDS_LINE_INT_NUM_ID0_1, + wait_line << 16 | wait_line); + rkcif_write_register(dev, CIF_REG_MIPI_LVDS_LINE_INT_NUM_ID2_3, + wait_line << 16 | wait_line); + + rkcif_write_register_or(dev, CIF_REG_MIPI_LVDS_INTEN, + CSI_DMA_END_INTEN(channel->id)); + + rkcif_write_register_or(dev, CIF_REG_MIPI_LVDS_INTEN, + CSI_ALL_ERROR_INTEN_V1); + } if (stream->cifdev->id_use_cnt == 0) { val = CIF_MIPI_LVDS_SW_PRESS_VALUE_RK3588(0x3) | CIF_MIPI_LVDS_SW_PRESS_ENABLE | @@ -3670,25 +3891,26 @@ static int rkcif_csi_channel_set_v1(struct rkcif_stream *stream, else val |= CIF_MIPI_LVDS_SW_SEL_LVDS_RV1106; rkcif_write_register(dev, CIF_REG_MIPI_LVDS_CTRL, val); - - rkcif_write_register_or(dev, CIF_REG_MIPI_LVDS_INTEN, - CSI_ALL_ERROR_INTEN_V1); } #if IS_ENABLED(CONFIG_CPU_RV1106) if (channel->id == 1) rv1106_sdmmc_get_lock(); #endif + if (capture_info->mode == RKMODULE_MULTI_DEV_COMBINE_ONE && + priv && priv->mode.rdbk_mode == RKISP_VICAP_ONLINE && + (dev->hdr.hdr_mode == NO_HDR || + (dev->hdr.hdr_mode == HDR_X2 && stream->id == 1) || + (dev->hdr.hdr_mode == HDR_X3 && stream->id == 2))) + offset = channel->capture_info.multi_dev.pixel_offset; + rkcif_write_register(dev, get_reg_index_of_id_ctrl1(channel->id), - channel->width | (channel->height << 16)); + (channel->width + offset) | (channel->height << 16)); #if IS_ENABLED(CONFIG_CPU_RV1106) if (channel->id == 1) rv1106_sdmmc_put_lock(); #endif - rkcif_write_register(dev, get_reg_index_of_frm0_y_vlw(channel->id), - channel->virtual_width); - if (channel->crop_en) rkcif_write_register(dev, get_reg_index_of_id_crop_start(channel->id), channel->crop_st_y << 16 | channel->crop_st_x); @@ -3706,6 +3928,17 @@ static int rkcif_csi_channel_set_v1(struct rkcif_stream *stream, rkcif_assign_new_buffer_pingpong_rockit(stream, RKCIF_YUV_ADDR_STATE_INIT, channel->id); + + if (capture_info->mode == RKMODULE_MULTI_DEV_COMBINE_ONE && + index == (capture_info->multi_dev.dev_num - 1) && + priv && priv->mode.rdbk_mode != RKISP_VICAP_ONLINE) + rkcif_write_register(dev, get_reg_index_of_id_crop_start(channel->id), + channel->crop_st_y << 16 | + (channel->crop_st_x + capture_info->multi_dev.pixel_offset)); + + rkcif_write_register(dev, get_reg_index_of_frm0_y_vlw(channel->id), + channel->virtual_width); + if (stream->lack_buf_cnt == 2) stream->dma_en = 0; @@ -3768,7 +4001,24 @@ static int rkcif_csi_channel_set_v1(struct rkcif_stream *stream, } if (dev->chip_id >= CHIP_RV1106_CIF) rkcif_modify_frame_skip_config(stream); - stream->cifdev->id_use_cnt++; + if (capture_info->mode == RKMODULE_MULTI_DEV_COMBINE_ONE) { + if (index == (capture_info->multi_dev.dev_num - 1)) + stream->cifdev->id_use_cnt++; + } else { + stream->cifdev->id_use_cnt++; + } + if (!(capture_info->mode == RKMODULE_MULTI_DEV_COMBINE_ONE && + index < capture_info->multi_dev.dev_num - 1)) { + if (mode == RKCIF_STREAM_MODE_CAPTURE) + rkcif_assign_new_buffer_pingpong(stream, + RKCIF_YUV_ADDR_STATE_INIT, + channel->id); + else if (mode == RKCIF_STREAM_MODE_TOISP || + mode == RKCIF_STREAM_MODE_TOISP_RDBK) + rkcif_assign_new_buffer_pingpong_toisp(stream, + RKCIF_YUV_ADDR_STATE_INIT, + channel->id); + } return 0; } @@ -3780,6 +4030,7 @@ static int rkcif_csi_stream_start(struct rkcif_stream *stream, unsigned int mode enum v4l2_mbus_type mbus_type = active_sensor->mbus.type; struct csi_channel_info *channel; u32 ret = 0; + int i; if (stream->state < RKCIF_STATE_STREAMING) { stream->frame_idx = 0; @@ -3818,10 +4069,18 @@ static int rkcif_csi_stream_start(struct rkcif_stream *stream, unsigned int mode } else if (mode == RKCIF_STREAM_MODE_ROCKIT) { stream->dma_en |= RKCIF_DMAEN_BY_ROCKIT; } - if (stream->cifdev->chip_id < CHIP_RK3588_CIF) + if (stream->cifdev->chip_id < CHIP_RK3588_CIF) { rkcif_csi_channel_set(stream, channel, mbus_type); - else - rkcif_csi_channel_set_v1(stream, channel, mbus_type, mode); + } else { + if (channel->capture_info.mode == RKMODULE_MULTI_DEV_COMBINE_ONE) { + for (i = 0; i < channel->capture_info.multi_dev.dev_num; i++) { + dev->csi_host_idx = channel->capture_info.multi_dev.dev_idx[i]; + rkcif_csi_channel_set_v1(stream, channel, mbus_type, mode, i); + } + } else { + rkcif_csi_channel_set_v1(stream, channel, mbus_type, mode, 0); + } + } } else { if (stream->cifdev->chip_id >= CHIP_RK3588_CIF) { if (mode == RKCIF_STREAM_MODE_CAPTURE) { @@ -3861,7 +4120,9 @@ static void rkcif_stream_stop(struct rkcif_stream *stream) struct v4l2_mbus_config *mbus_cfg = &cif_dev->active_sensor->mbus; u32 val; int id; + int i = 0; + stream->cifdev->id_use_cnt--; if (mbus_cfg->type == V4L2_MBUS_CSI2_DPHY || mbus_cfg->type == V4L2_MBUS_CSI2_CPHY || mbus_cfg->type == V4L2_MBUS_CCP2) { @@ -3873,7 +4134,14 @@ static void rkcif_stream_stop(struct rkcif_stream *stream) else val &= ~LVDS_ENABLE_CAPTURE; - rkcif_write_register(cif_dev, get_reg_index_of_id_ctrl0(id), val); + if (cif_dev->channels[id].capture_info.mode == RKMODULE_MULTI_DEV_COMBINE_ONE) { + for (i = 0; i < cif_dev->channels[id].capture_info.multi_dev.dev_num; i++) { + cif_dev->csi_host_idx = cif_dev->channels[id].capture_info.multi_dev.dev_idx[i]; + rkcif_write_register(cif_dev, get_reg_index_of_id_ctrl0(id), val); + } + } else { + rkcif_write_register(cif_dev, get_reg_index_of_id_ctrl0(id), val); + } rkcif_write_register_or(cif_dev, CIF_REG_MIPI_LVDS_INTSTAT, CSI_START_INTSTAT(id) | @@ -3892,8 +4160,16 @@ static void rkcif_stream_stop(struct rkcif_stream *stream) if (stream->cifdev->id_use_cnt == 0) { rkcif_write_register_and(cif_dev, CIF_REG_MIPI_LVDS_INTEN, ~CSI_ALL_ERROR_INTEN_V1); - rkcif_write_register_and(cif_dev, CIF_REG_MIPI_LVDS_CTRL, - ~CSI_ENABLE_CAPTURE); + if (cif_dev->channels[id].capture_info.mode == RKMODULE_MULTI_DEV_COMBINE_ONE) { + for (i = 0; i < cif_dev->channels[id].capture_info.multi_dev.dev_num; i++) { + cif_dev->csi_host_idx = cif_dev->channels[id].capture_info.multi_dev.dev_idx[i]; + rkcif_write_register_and(cif_dev, CIF_REG_MIPI_LVDS_CTRL, + ~CSI_ENABLE_CAPTURE); + } + } else { + rkcif_write_register_and(cif_dev, CIF_REG_MIPI_LVDS_CTRL, + ~CSI_ENABLE_CAPTURE); + } } } @@ -3909,7 +4185,6 @@ static void rkcif_stream_stop(struct rkcif_stream *stream) rkcif_config_dvp_pin(cif_dev, false); } } - stream->cifdev->id_use_cnt--; stream->state = RKCIF_STATE_READY; stream->dma_en = 0; } @@ -4006,6 +4281,8 @@ static void rkcif_check_buffer_update_pingpong(struct rkcif_stream *stream, u32 frm_addr_y = 0, frm_addr_uv = 0; u32 frm0_addr_y = 0, frm0_addr_uv = 0; u32 frm1_addr_y = 0, frm1_addr_uv = 0; + u32 buff_addr_y = 0, buff_addr_cbcr = 0; + struct rkmodule_capture_info *capture_info = &dev->channels[channel_id].capture_info; unsigned long flags; int frame_phase = 0; bool is_dual_update_buf = false; @@ -4072,22 +4349,51 @@ static void rkcif_check_buffer_update_pingpong(struct rkcif_stream *stream, } if (buffer) { if (is_dual_update_buf) { - rkcif_write_register(dev, frm0_addr_y, - buffer->buff_addr[RKCIF_PLANE_Y]); - if (stream->cif_fmt_out->fmt_type != CIF_FMT_TYPE_RAW) - rkcif_write_register(dev, frm0_addr_uv, - buffer->buff_addr[RKCIF_PLANE_CBCR]); - rkcif_write_register(dev, frm1_addr_y, - buffer->buff_addr[RKCIF_PLANE_Y]); - if (stream->cif_fmt_out->fmt_type != CIF_FMT_TYPE_RAW) - rkcif_write_register(dev, frm1_addr_uv, - buffer->buff_addr[RKCIF_PLANE_CBCR]); + buff_addr_y = buffer->buff_addr[RKCIF_PLANE_Y]; + buff_addr_cbcr = buffer->buff_addr[RKCIF_PLANE_CBCR]; + if (capture_info->mode == RKMODULE_MULTI_DEV_COMBINE_ONE) { + rkcif_write_buff_addr_multi_dev_combine(stream, + frm0_addr_y, + frm0_addr_uv, + buff_addr_y, + buff_addr_cbcr, + false); + rkcif_write_buff_addr_multi_dev_combine(stream, + frm1_addr_y, + frm1_addr_uv, + buff_addr_y, + buff_addr_cbcr, + false); + } else { + rkcif_write_register(dev, frm0_addr_y, buff_addr_y); + if (stream->cif_fmt_out->fmt_type != CIF_FMT_TYPE_RAW) + rkcif_write_register(dev, + frm0_addr_uv, + buff_addr_cbcr); + rkcif_write_register(dev, frm1_addr_y, buff_addr_y); + if (stream->cif_fmt_out->fmt_type != CIF_FMT_TYPE_RAW) + rkcif_write_register(dev, + frm1_addr_uv, + buff_addr_cbcr); + } } else { - rkcif_write_register(dev, frm_addr_y, - buffer->buff_addr[RKCIF_PLANE_Y]); - if (stream->cif_fmt_out->fmt_type != CIF_FMT_TYPE_RAW) - rkcif_write_register(dev, frm_addr_uv, - buffer->buff_addr[RKCIF_PLANE_CBCR]); + + buff_addr_y = buffer->buff_addr[RKCIF_PLANE_Y]; + buff_addr_cbcr = buffer->buff_addr[RKCIF_PLANE_CBCR]; + if (capture_info->mode == RKMODULE_MULTI_DEV_COMBINE_ONE) { + rkcif_write_buff_addr_multi_dev_combine(stream, + frm_addr_y, + frm_addr_uv, + buff_addr_y, + buff_addr_cbcr, + false); + } else { + rkcif_write_register(dev, frm_addr_y, buff_addr_y); + if (stream->cif_fmt_out->fmt_type != CIF_FMT_TYPE_RAW) + rkcif_write_register(dev, + frm_addr_uv, + buff_addr_cbcr); + } } } } else { @@ -5600,6 +5906,7 @@ static void rkcif_attach_sync_mode(struct rkcif_device *cifdev) { struct rkcif_hw *hw = cifdev->hw_dev; struct rkcif_device *dev; + struct sditf_priv *priv; int i = 0, j = 0; int ret = 0; int count = 0; @@ -5677,26 +5984,31 @@ static void rkcif_attach_sync_mode(struct rkcif_device *cifdev) else sync_cfg.group = 0; } else { - for (j = 0; j < dev->sditf_cnt; j++) { - ret |= v4l2_subdev_call(dev->sditf[j]->sensor_sd, - core, ioctl, - RKMODULE_GET_SYNC_MODE, - &sync_type); - if (!ret && sync_type) - break; + priv = dev->sditf[0]; + if (priv && priv->is_combine_mode && dev->sditf_cnt <= RKCIF_MAX_SDITF) { + for (j = 0; j < dev->sditf_cnt; j++) { + ret |= v4l2_subdev_call(dev->sditf[j]->sensor_sd, + core, ioctl, + RKMODULE_GET_SYNC_MODE, + &sync_type); + if (!ret && sync_type) { + priv = dev->sditf[j]; + break; + } + } + if (!ret) + sync_cfg.type = sync_type; + else + sync_cfg.type = NO_SYNC_MODE; + ret = v4l2_subdev_call(priv->sensor_sd, + core, ioctl, + RKMODULE_GET_GROUP_ID, + &sync_group); + if (!ret && sync_group < RKCIF_MAX_GROUP) + sync_cfg.group = sync_group; + else + sync_cfg.group = 0; } - if (!ret) - sync_cfg.type = sync_type; - else - sync_cfg.type = NO_SYNC_MODE; - ret = v4l2_subdev_call(dev->sditf[j]->sensor_sd, - core, ioctl, - RKMODULE_GET_GROUP_ID, - &sync_group); - if (!ret && sync_group < RKCIF_MAX_GROUP) - sync_cfg.group = sync_group; - else - sync_cfg.group = 0; } if (sync_cfg.group == cifdev->sync_cfg.group) { if (sync_cfg.type == EXTERNAL_MASTER_MODE) { @@ -5719,6 +6031,11 @@ static void rkcif_attach_sync_mode(struct rkcif_device *cifdev) sync_config->sync_mask |= BIT(dev->csi_host_idx); } dev->sync_cfg = sync_cfg; + } else { + ret = v4l2_subdev_call(dev->terminal_sensor.sd, + core, ioctl, + RKMODULE_GET_SYNC_MODE, + &sync_type); } } if (sync_config->int_master.count == 1) { @@ -5752,15 +6069,18 @@ int rkcif_do_start_stream(struct rkcif_stream *stream, unsigned int mode) struct rkcif_hw *hw_dev = dev->hw_dev; struct v4l2_device *v4l2_dev = &dev->v4l2_dev; struct rkcif_sensor_info *sensor_info = dev->active_sensor; - struct rkcif_sensor_info *terminal_sensor = &dev->terminal_sensor; + struct rkcif_sensor_info *terminal_sensor = NULL; struct rkmodule_hdr_cfg hdr_cfg; + struct rkcif_csi_info csi_info = {0}; int rkmodule_stream_seq = RKMODULE_START_STREAM_DEFAULT; int ret; + int i = 0; v4l2_info(&dev->v4l2_dev, "stream[%d] start streaming\n", stream->id); rkcif_attach_sync_mode(dev); mutex_lock(&dev->stream_lock); + if ((stream->cur_stream_mode & RKCIF_STREAM_MODE_CAPTURE) == mode) { ret = -EBUSY; v4l2_err(v4l2_dev, "stream in busy state\n"); @@ -5773,7 +6093,7 @@ int rkcif_do_start_stream(struct rkcif_stream *stream, unsigned int mode) else stream->is_line_inten = false; - if (dev->active_sensor) { + if (!dev->active_sensor) { ret = rkcif_update_sensor_info(stream); if (ret < 0) { v4l2_err(v4l2_dev, @@ -5782,7 +6102,7 @@ int rkcif_do_start_stream(struct rkcif_stream *stream, unsigned int mode) goto out; } } - + terminal_sensor = &dev->terminal_sensor; if (terminal_sensor->sd) { ret = v4l2_subdev_call(terminal_sensor->sd, core, ioctl, @@ -5813,6 +6133,34 @@ int rkcif_do_start_stream(struct rkcif_stream *stream, unsigned int mode) goto destroy_buf; mutex_lock(&hw_dev->dev_lock); + if (atomic_read(&dev->pipe.stream_cnt) == 0 && + dev->active_sensor && + (dev->active_sensor->mbus.type == V4L2_MBUS_CSI2_DPHY || + dev->active_sensor->mbus.type == V4L2_MBUS_CSI2_CPHY || + dev->active_sensor->mbus.type == V4L2_MBUS_CCP2)) { + if (dev->channels[0].capture_info.mode == RKMODULE_MULTI_DEV_COMBINE_ONE) { + csi_info.csi_num = dev->channels[0].capture_info.multi_dev.dev_num; + if (csi_info.csi_num > RKCIF_MAX_CSI_NUM) { + v4l2_err(v4l2_dev, + "csi num %d, max %d\n", + csi_info.csi_num, RKCIF_MAX_CSI_NUM); + goto out; + } + for (i = 0; i < csi_info.csi_num; i++) + csi_info.csi_idx[i] = dev->channels[0].capture_info.multi_dev.dev_idx[i]; + } else { + csi_info.csi_num = 1; + csi_info.csi_idx[0] = dev->csi_host_idx; + } + ret = v4l2_subdev_call(dev->active_sensor->sd, + core, ioctl, + RKCIF_CMD_SET_CSI_IDX, + &csi_info); + if (ret) + v4l2_err(&dev->v4l2_dev, "set csi idx %d fail\n", dev->csi_host_idx); + + } + if (((dev->active_sensor && dev->active_sensor->mbus.type == V4L2_MBUS_BT656) || dev->is_use_dummybuf) && (!dev->hw_dev->dummy_buf.vaddr) && @@ -5980,6 +6328,7 @@ int rkcif_set_fmt(struct rkcif_stream *stream, bool try) { struct rkcif_device *dev = stream->cifdev; + struct sditf_priv *priv = dev->sditf[0]; const struct cif_output_fmt *fmt; const struct cif_input_fmt *cif_fmt_in = NULL; struct v4l2_rect input_rect; @@ -5987,6 +6336,7 @@ int rkcif_set_fmt(struct rkcif_stream *stream, u32 xsubs = 1, ysubs = 1, i; struct rkmodule_hdr_cfg hdr_cfg; struct rkcif_extend_info *extend_line = &stream->extend_line; + struct csi_channel_info *channel_info = &dev->channels[stream->id]; int ret; for (i = 0; i < RKCIF_MAX_PLANE; i++) @@ -6002,7 +6352,7 @@ int rkcif_set_fmt(struct rkcif_stream *stream, if (dev->terminal_sensor.sd) { cif_fmt_in = get_input_fmt(dev->terminal_sensor.sd, &input_rect, stream->id, - &dev->channels[stream->id]); + channel_info); stream->cif_fmt_in = cif_fmt_in; } else { v4l2_err(&stream->cifdev->v4l2_dev, @@ -6044,8 +6394,9 @@ int rkcif_set_fmt(struct rkcif_stream *stream, planes = fmt->cplanes ? fmt->cplanes : fmt->mplanes; - if (cif_fmt_in && (cif_fmt_in->mbus_code == MEDIA_BUS_FMT_SPD_2X8 || - cif_fmt_in->mbus_code == MEDIA_BUS_FMT_EBD_1X8)) + if (cif_fmt_in && + (cif_fmt_in->mbus_code == MEDIA_BUS_FMT_SPD_2X8 || + cif_fmt_in->mbus_code == MEDIA_BUS_FMT_EBD_1X8)) stream->crop_enable = false; for (i = 0; i < planes; i++) { @@ -6070,7 +6421,7 @@ int rkcif_set_fmt(struct rkcif_stream *stream, } } - if (dev->sditf_cnt > 1 && dev->sditf_cnt <= RKCIF_MAX_SDITF) + if (priv && priv->is_combine_mode && dev->sditf_cnt <= RKCIF_MAX_SDITF) height *= dev->sditf_cnt; extend_line->pixm.height = height + RKMODULE_EXTEND_LINE; @@ -6080,8 +6431,9 @@ int rkcif_set_fmt(struct rkcif_stream *stream, * to optimize reading and writing of ddr, aliged with 256. */ if (fmt->fmt_type == CIF_FMT_TYPE_RAW && - (stream->cif_fmt_in->mbus_code == MEDIA_BUS_FMT_EBD_1X8 || - stream->cif_fmt_in->mbus_code == MEDIA_BUS_FMT_SPD_2X8)) { + cif_fmt_in && + (cif_fmt_in->mbus_code == MEDIA_BUS_FMT_EBD_1X8 || + cif_fmt_in->mbus_code == MEDIA_BUS_FMT_SPD_2X8)) { stream->is_compact = false; } @@ -8499,8 +8851,8 @@ static void rkcif_update_stream(struct rkcif_device *cif_dev, if (!stream->is_line_wake_up) { ret = rkcif_assign_new_buffer_pingpong(stream, - RKCIF_YUV_ADDR_STATE_UPDATE, - mipi_id); + RKCIF_YUV_ADDR_STATE_UPDATE, + mipi_id); if (ret && cif_dev->chip_id < CHIP_RK3588_CIF) return; } else { @@ -8634,6 +8986,7 @@ static int rkcif_do_reset_work(struct rkcif_device *cif_dev, struct rkcif_sensor_info *terminal_sensor = &cif_dev->terminal_sensor; struct rkcif_resume_info *resume_info = &cif_dev->reset_work.resume_info; struct rkcif_timer *timer = &cif_dev->reset_watchdog_timer; + struct sditf_priv *priv = cif_dev->sditf[0]; int i, j, ret = 0; u32 on, sof_cnt; int capture_mode = 0; @@ -8702,10 +9055,12 @@ static int rkcif_do_reset_work(struct rkcif_device *cif_dev, __func__, on ? "on" : "off", p->subdevs[i]->name); } - for (i = 0; i < cif_dev->sditf_cnt; i++) { - if (cif_dev->sditf[i] && cif_dev->sditf[i]->sensor_sd) - ret = v4l2_subdev_call(cif_dev->sditf[i]->sensor_sd, core, ioctl, - RKMODULE_SET_QUICK_STREAM, &on); + if (priv && priv->is_combine_mode && cif_dev->sditf_cnt <= RKCIF_MAX_SDITF) { + for (i = 0; i < cif_dev->sditf_cnt; i++) { + if (cif_dev->sditf[i] && cif_dev->sditf[i]->sensor_sd) + ret = v4l2_subdev_call(cif_dev->sditf[i]->sensor_sd, core, ioctl, + RKMODULE_SET_QUICK_STREAM, &on); + } } rockchip_clear_system_status(SYS_STATUS_CIF0); @@ -8800,10 +9155,12 @@ static int rkcif_do_reset_work(struct rkcif_device *cif_dev, p->subdevs[i]->name); } - for (i = 0; i < cif_dev->sditf_cnt; i++) { - if (cif_dev->sditf[i] && cif_dev->sditf[i]->sensor_sd) - v4l2_subdev_call(cif_dev->sditf[i]->sensor_sd, core, ioctl, - RKMODULE_SET_QUICK_STREAM, &on); + if (priv && priv->is_combine_mode && cif_dev->sditf_cnt <= RKCIF_MAX_SDITF) { + for (i = 0; i < cif_dev->sditf_cnt; i++) { + if (cif_dev->sditf[i] && cif_dev->sditf[i]->sensor_sd) + v4l2_subdev_call(cif_dev->sditf[i]->sensor_sd, core, ioctl, + RKMODULE_SET_QUICK_STREAM, &on); + } } if (cif_dev->chip_id < CHIP_RK3588_CIF) diff --git a/drivers/media/platform/rockchip/cif/dev.c b/drivers/media/platform/rockchip/cif/dev.c index f9081634bcd6..e931dc61389d 100644 --- a/drivers/media/platform/rockchip/cif/dev.c +++ b/drivers/media/platform/rockchip/cif/dev.c @@ -1571,16 +1571,6 @@ static int subdev_notifier_complete(struct v4l2_async_notifier *notifier) if (!completion_done(&dev->cmpl_ntf)) complete(&dev->cmpl_ntf); - if (dev->active_sensor && - (dev->active_sensor->mbus.type == V4L2_MBUS_CSI2_DPHY || - dev->active_sensor->mbus.type == V4L2_MBUS_CSI2_CPHY)) { - ret = v4l2_subdev_call(dev->active_sensor->sd, - core, ioctl, - RKCIF_CMD_SET_CSI_IDX, - &dev->csi_host_idx); - if (ret) - v4l2_err(&dev->v4l2_dev, "set csi idx %d fail\n", dev->csi_host_idx); - } v4l2_info(&dev->v4l2_dev, "Async subdev notifier completed\n"); return ret; @@ -1950,6 +1940,7 @@ int rkcif_plat_init(struct rkcif_device *cif_dev, struct device_node *node, int cif_dev->early_line = 0; cif_dev->is_thunderboot = false; cif_dev->rdbk_debug = 0; + memset(&cif_dev->channels[0].capture_info, 0, sizeof(cif_dev->channels[0].capture_info)); if (cif_dev->chip_id == CHIP_RV1126_CIF_LITE) cif_dev->isr_hdl = rkcif_irq_lite_handler; diff --git a/drivers/media/platform/rockchip/cif/dev.h b/drivers/media/platform/rockchip/cif/dev.h index 8cdfab14fd27..c0974a8c7719 100644 --- a/drivers/media/platform/rockchip/cif/dev.h +++ b/drivers/media/platform/rockchip/cif/dev.h @@ -280,10 +280,12 @@ struct csi_channel_info { unsigned int width; unsigned int height; unsigned int virtual_width; + unsigned int left_virtual_width; unsigned int crop_st_x; unsigned int crop_st_y; unsigned int dsi_input; struct rkmodule_lvds_cfg lvds_cfg; + struct rkmodule_capture_info capture_info; }; struct rkcif_vdev_node { diff --git a/drivers/media/platform/rockchip/cif/hw.c b/drivers/media/platform/rockchip/cif/hw.c index 55179f795866..af0f0633e7bb 100644 --- a/drivers/media/platform/rockchip/cif/hw.c +++ b/drivers/media/platform/rockchip/cif/hw.c @@ -1506,6 +1506,7 @@ int rk_cif_plat_drv_init(void) ret = platform_driver_register(&rkcif_hw_plat_drv); if (ret) return ret; + rkcif_csi2_hw_plat_drv_init(); return rkcif_csi2_plat_drv_init(); } @@ -1513,6 +1514,7 @@ static void __exit rk_cif_plat_drv_exit(void) { platform_driver_unregister(&rkcif_hw_plat_drv); rkcif_csi2_plat_drv_exit(); + rkcif_csi2_hw_plat_drv_exit(); } #if defined(CONFIG_VIDEO_ROCKCHIP_THUNDER_BOOT_ISP) && !defined(CONFIG_INITCALL_ASYNC) diff --git a/drivers/media/platform/rockchip/cif/mipi-csi2.c b/drivers/media/platform/rockchip/cif/mipi-csi2.c index c0e5999d325b..f526b4392221 100644 --- a/drivers/media/platform/rockchip/cif/mipi-csi2.c +++ b/drivers/media/platform/rockchip/cif/mipi-csi2.c @@ -13,12 +13,12 @@ #include #include #include +#include #include #include #include #include #include "mipi-csi2.h" -#include #include static int csi2_debug; @@ -147,47 +147,55 @@ static void csi2_update_sensor_info(struct csi2_dev *csi2) } -static void csi2_hw_do_reset(struct csi2_dev *csi2) +static void csi2_hw_do_reset(struct csi2_hw *csi2_hw) { - reset_control_assert(csi2->rsts_bulk); + + if (!csi2_hw->rsts_bulk) + return; + + reset_control_assert(csi2_hw->rsts_bulk); udelay(5); - reset_control_deassert(csi2->rsts_bulk); + reset_control_deassert(csi2_hw->rsts_bulk); } -static int csi2_enable_clks(struct csi2_dev *csi2) +static int csi2_enable_clks(struct csi2_hw *csi2_hw) { int ret = 0; - ret = clk_bulk_prepare_enable(csi2->clks_num, csi2->clks_bulk); + if (!csi2_hw->clks_bulk) + return -EINVAL; + + ret = clk_bulk_prepare_enable(csi2_hw->clks_num, csi2_hw->clks_bulk); if (ret) - dev_err(csi2->dev, "failed to enable clks\n"); + dev_err(csi2_hw->dev, "failed to enable clks\n"); return ret; } -static void csi2_disable_clks(struct csi2_dev *csi2) +static void csi2_disable_clks(struct csi2_hw *csi2_hw) { - clk_bulk_disable_unprepare(csi2->clks_num, csi2->clks_bulk); + if (!csi2_hw->clks_bulk) + return; + clk_bulk_disable_unprepare(csi2_hw->clks_num, csi2_hw->clks_bulk); } -static void csi2_disable(struct csi2_dev *csi2) +static void csi2_disable(struct csi2_hw *csi2_hw) { - void __iomem *base = csi2->base; - - write_csihost_reg(base, CSIHOST_RESETN, 0); - write_csihost_reg(base, CSIHOST_MSK1, 0xffffffff); - write_csihost_reg(base, CSIHOST_MSK2, 0xffffffff); + write_csihost_reg(csi2_hw->base, CSIHOST_RESETN, 0); + write_csihost_reg(csi2_hw->base, CSIHOST_MSK1, 0xffffffff); + write_csihost_reg(csi2_hw->base, CSIHOST_MSK2, 0xffffffff); } static int csi2_g_mbus_config(struct v4l2_subdev *sd, unsigned int pad_id, struct v4l2_mbus_config *mbus); -static void csi2_enable(struct csi2_dev *csi2, +static void csi2_enable(struct csi2_hw *csi2_hw, enum host_type_t host_type) { - void __iomem *base = csi2->base; + void __iomem *base = csi2_hw->base; + struct csi2_dev *csi2 = csi2_hw->csi2; int lanes = csi2->bus.num_data_lanes; struct v4l2_mbus_config mbus; u32 val = 0; @@ -225,16 +233,10 @@ static int csi2_start(struct csi2_dev *csi2) { enum host_type_t host_type; int ret, i; + int csi_idx = 0; atomic_set(&csi2->frm_sync_seq, 0); - csi2_hw_do_reset(csi2); - ret = csi2_enable_clks(csi2); - if (ret) { - v4l2_err(&csi2->sd, "%s: enable clks failed\n", __func__); - return ret; - } - csi2_update_sensor_info(csi2); if (csi2->dsi_input_en == RKMODULE_DSI_INPUT) @@ -242,7 +244,16 @@ static int csi2_start(struct csi2_dev *csi2) else host_type = RK_CSI_RXHOST; - csi2_enable(csi2, host_type); + for (i = 0; i < csi2->csi_info.csi_num; i++) { + csi_idx = csi2->csi_info.csi_idx[i]; + csi2_hw_do_reset(csi2->csi2_hw[csi_idx]); + ret = csi2_enable_clks(csi2->csi2_hw[csi_idx]); + if (ret) { + v4l2_err(&csi2->sd, "%s: enable clks failed\n", __func__); + return ret; + } + csi2_enable(csi2->csi2_hw[csi_idx], host_type); + } pr_debug("stream sd: %s\n", csi2->src_sd->name); ret = v4l2_subdev_call(csi2->src_sd, video, s_stream, 1); @@ -256,20 +267,29 @@ static int csi2_start(struct csi2_dev *csi2) return 0; err_assert_reset: - csi2_disable(csi2); - csi2_disable_clks(csi2); + for (i = 0; i < csi2->csi_info.csi_num; i++) { + csi_idx = csi2->csi_info.csi_idx[i]; + csi2_disable(csi2->csi2_hw[csi_idx]); + csi2_disable_clks(csi2->csi2_hw[csi_idx]); + } return ret; } static void csi2_stop(struct csi2_dev *csi2) { + int i = 0; + int csi_idx = 0; + /* stop upstream */ v4l2_subdev_call(csi2->src_sd, video, s_stream, 0); - csi2_disable(csi2); - csi2_hw_do_reset(csi2); - csi2_disable_clks(csi2); + for (i = 0; i < csi2->csi_info.csi_num; i++) { + csi_idx = csi2->csi_info.csi_idx[i]; + csi2_disable(csi2->csi2_hw[csi_idx]); + csi2_hw_do_reset(csi2->csi2_hw[csi_idx]); + csi2_disable_clks(csi2->csi2_hw[csi_idx]); + } } /* @@ -379,7 +399,6 @@ static int csi2_media_init(struct v4l2_subdev *sd) csi2->crop.left = 0; csi2->crop.width = RKCIF_DEFAULT_WIDTH; csi2->crop.height = RKCIF_DEFAULT_HEIGHT; - csi2->csi_idx = 0; return media_entity_pads_init(&sd->entity, num_pads, csi2->pad); } @@ -567,11 +586,19 @@ static int rkcif_csi2_s_power(struct v4l2_subdev *sd, int on) static long rkcif_csi2_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg) { struct csi2_dev *csi2 = sd_to_dev(sd); + struct v4l2_subdev *sensor = get_remote_sensor(sd); long ret = 0; + int i = 0; switch (cmd) { case RKCIF_CMD_SET_CSI_IDX: - csi2->csi_idx = *((u32 *)arg); + csi2->csi_info = *((struct rkcif_csi_info *)arg); + for (i = 0; i < csi2->csi_info.csi_num; i++) + csi2->csi2_hw[csi2->csi_info.csi_idx[i]]->csi2 = csi2; + if (csi2->match_data->chip_id > CHIP_RV1126_CSI2) + ret = v4l2_subdev_call(sensor, core, ioctl, + RKCIF_CMD_SET_CSI_IDX, + arg); break; default: ret = -ENOIOCTLCMD; @@ -586,15 +613,15 @@ static long rkcif_csi2_compat_ioctl32(struct v4l2_subdev *sd, unsigned int cmd, unsigned long arg) { void __user *up = compat_ptr(arg); - u32 csi_idx = 0; + struct rkcif_csi_info csi_info; long ret; switch (cmd) { case RKCIF_CMD_SET_CSI_IDX: - if (copy_from_user(&csi_idx, up, sizeof(u32))) + if (copy_from_user(&csi_info, up, sizeof(struct rkcif_csi_info))) return -EFAULT; - ret = rkcif_csi2_ioctl(sd, cmd, &csi_idx); + ret = rkcif_csi2_ioctl(sd, cmd, &csi_info); break; default: ret = -ENOIOCTLCMD; @@ -749,7 +776,8 @@ static void csi2_find_err_vc(int val, char *vc_info) static irqreturn_t rk_csirx_irq1_handler(int irq, void *ctx) { struct device *dev = ctx; - struct csi2_dev *csi2 = sd_to_dev(dev_get_drvdata(dev)); + struct csi2_hw *csi2_hw = dev_get_drvdata(dev); + struct csi2_dev *csi2 = csi2_hw->csi2; struct csi2_err_stats *err_list = NULL; unsigned long err_stat = 0; u32 val; @@ -758,7 +786,7 @@ static irqreturn_t rk_csirx_irq1_handler(int irq, void *ctx) char vc_info[CSI_VCINFO_LEN] = {0}; bool is_add_cnt = false; - val = read_csihost_reg(csi2->base, CSIHOST_ERR1); + val = read_csihost_reg(csi2_hw->base, CSIHOST_ERR1); if (val) { if (val & CSIHOST_ERR1_PHYERR_SPTSYNCHS) { err_list = &csi2->err_list[RK_CSI2_ERR_SOTSYN]; @@ -767,7 +795,7 @@ static irqreturn_t rk_csirx_irq1_handler(int irq, void *ctx) if (err_list->cnt > 3 && csi2->err_list[RK_CSI2_ERR_ALL].cnt <= err_list->cnt) { csi2->is_check_sot_sync = false; - write_csihost_reg(csi2->base, CSIHOST_MSK1, 0xf); + write_csihost_reg(csi2_hw->base, CSIHOST_MSK1, 0xf); } if (csi2->is_check_sot_sync) { csi2_find_err_vc(val & 0xf, vc_info); @@ -832,7 +860,7 @@ static irqreturn_t rk_csirx_irq1_handler(int irq, void *ctx) csi2_err_strncat(err_str, cur_str); } - pr_err("%s ERR1:0x%x %s\n", csi2->dev_name, val, err_str); + pr_err("%s ERR1:0x%x %s\n", csi2_hw->dev_name, val, err_str); if (is_add_cnt) { csi2->err_list[RK_CSI2_ERR_ALL].cnt++; @@ -841,7 +869,7 @@ static irqreturn_t rk_csirx_irq1_handler(int irq, void *ctx) atomic_notifier_call_chain(&g_csi_host_chain, err_stat, - &csi2->csi_idx); + &csi2->csi_info.csi_idx[csi2->csi_info.csi_num - 1]); } } @@ -852,13 +880,13 @@ static irqreturn_t rk_csirx_irq1_handler(int irq, void *ctx) static irqreturn_t rk_csirx_irq2_handler(int irq, void *ctx) { struct device *dev = ctx; - struct csi2_dev *csi2 = sd_to_dev(dev_get_drvdata(dev)); + struct csi2_hw *csi2_hw = dev_get_drvdata(dev); u32 val; char cur_str[CSI_ERRSTR_LEN] = {0}; char err_str[CSI_ERRSTR_LEN] = {0}; char vc_info[CSI_VCINFO_LEN] = {0}; - val = read_csihost_reg(csi2->base, CSIHOST_ERR2); + val = read_csihost_reg(csi2_hw->base, CSIHOST_ERR2); if (val) { if (val & CSIHOST_ERR2_PHYERR_ESC) { csi2_find_err_vc(val & 0xf, vc_info); @@ -885,7 +913,7 @@ static irqreturn_t rk_csirx_irq2_handler(int irq, void *ctx) csi2_err_strncat(err_str, cur_str); } - pr_err("%s ERR2:0x%x %s\n", csi2->dev_name, val, err_str); + pr_err("%s ERR2:0x%x %s\n", csi2_hw->dev_name, val, err_str); } return IRQ_HANDLED; @@ -924,31 +952,43 @@ static int csi2_notifier(struct csi2_dev *csi2) static const struct csi2_match_data rk1808_csi2_match_data = { .chip_id = CHIP_RK1808_CSI2, .num_pads = CSI2_NUM_PADS, + .num_hw = 1, }; static const struct csi2_match_data rk3288_csi2_match_data = { .chip_id = CHIP_RK3288_CSI2, .num_pads = CSI2_NUM_PADS_SINGLE_LINK, + .num_hw = 1, }; static const struct csi2_match_data rv1126_csi2_match_data = { .chip_id = CHIP_RV1126_CSI2, .num_pads = CSI2_NUM_PADS, + .num_hw = 1, }; static const struct csi2_match_data rk3568_csi2_match_data = { .chip_id = CHIP_RK3568_CSI2, .num_pads = CSI2_NUM_PADS, + .num_hw = 1, }; static const struct csi2_match_data rk3588_csi2_match_data = { .chip_id = CHIP_RK3588_CSI2, .num_pads = CSI2_NUM_PADS_MAX, + .num_hw = 6, +}; + +static const struct csi2_match_data rv1106_csi2_match_data = { + .chip_id = CHIP_RV1106_CSI2, + .num_pads = CSI2_NUM_PADS_MAX, + .num_hw = 2, }; static const struct csi2_match_data rk3562_csi2_match_data = { .chip_id = CHIP_RK3562_CSI2, .num_pads = CSI2_NUM_PADS_MAX, + .num_hw = 4, }; static const struct of_device_id csi2_dt_ids[] = { @@ -972,6 +1012,10 @@ static const struct of_device_id csi2_dt_ids[] = { .compatible = "rockchip,rk3588-mipi-csi2", .data = &rk3588_csi2_match_data, }, + { + .compatible = "rockchip,rv1106-mipi-csi2", + .data = &rv1106_csi2_match_data, + }, { .compatible = "rockchip,rk3562-mipi-csi2", .data = &rk3562_csi2_match_data, @@ -980,15 +1024,48 @@ static const struct of_device_id csi2_dt_ids[] = { }; MODULE_DEVICE_TABLE(of, csi2_dt_ids); +static int csi2_attach_hw(struct csi2_dev *csi2) +{ + struct device_node *np; + struct platform_device *pdev; + struct csi2_hw *hw; + int i = 0; + + for (i = 0; i < csi2->match_data->num_hw; i++) { + np = of_parse_phandle(csi2->dev->of_node, "rockchip,hw", i); + if (!np || !of_device_is_available(np)) { + dev_err(csi2->dev, "failed to get csi2 hw node\n"); + return -ENODEV; + } + + pdev = of_find_device_by_node(np); + of_node_put(np); + if (!pdev) { + dev_err(csi2->dev, "failed to get csi2 hw from node\n"); + return -ENODEV; + } + + hw = platform_get_drvdata(pdev); + if (!hw) { + dev_err(csi2->dev, "failed attach csi2 hw\n"); + return -EINVAL; + } + + hw->csi2 = csi2; + csi2->csi2_hw[i] = hw; + } + dev_info(csi2->dev, "attach to csi2 hw node\n"); + + return 0; +} + static int csi2_probe(struct platform_device *pdev) { const struct of_device_id *match; - struct device *dev = &pdev->dev; struct device_node *node = pdev->dev.of_node; struct csi2_dev *csi2 = NULL; - struct resource *res; const struct csi2_match_data *data; - int ret, irq; + int ret; match = of_match_node(csi2_dt_ids, node); if (IS_ERR(match)) @@ -1014,63 +1091,11 @@ static int csi2_probe(struct platform_device *pdev) v4l2_err(&csi2->sd, "failed to copy name\n"); platform_set_drvdata(pdev, &csi2->sd); - csi2->clks_num = devm_clk_bulk_get_all(dev, &csi2->clks_bulk); - if (csi2->clks_num < 0) { - csi2->clks_num = 0; - dev_err(dev, "failed to get csi2 clks\n"); + ret = csi2_attach_hw(csi2); + if (ret) { + v4l2_err(&csi2->sd, "must enable all mipi csi2 hw node\n"); + return -EINVAL; } - - csi2->rsts_bulk = devm_reset_control_array_get_optional_exclusive(dev); - if (IS_ERR(csi2->rsts_bulk)) { - if (PTR_ERR(csi2->rsts_bulk) != -EPROBE_DEFER) - dev_err(dev, "failed to get csi2 reset\n"); - csi2->rsts_bulk = NULL; - } - - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - csi2->base = devm_ioremap_resource(&pdev->dev, res); - if (IS_ERR(csi2->base)) { - resource_size_t offset = res->start; - resource_size_t size = resource_size(res); - - dev_warn(&pdev->dev, "avoid secondary mipi resource check!\n"); - - csi2->base = devm_ioremap(&pdev->dev, offset, size); - if (IS_ERR(csi2->base)) { - dev_err(&pdev->dev, "Failed to ioremap resource\n"); - - return PTR_ERR(csi2->base); - } - } - - irq = platform_get_irq_byname(pdev, "csi-intr1"); - if (irq > 0) { - ret = devm_request_irq(&pdev->dev, irq, - rk_csirx_irq1_handler, 0, - dev_driver_string(&pdev->dev), - &pdev->dev); - if (ret < 0) - v4l2_err(&csi2->sd, "request csi-intr1 irq failed: %d\n", - ret); - csi2->irq1 = irq; - } else { - v4l2_err(&csi2->sd, "No found irq csi-intr1\n"); - } - - irq = platform_get_irq_byname(pdev, "csi-intr2"); - if (irq > 0) { - ret = devm_request_irq(&pdev->dev, irq, - rk_csirx_irq2_handler, 0, - dev_driver_string(&pdev->dev), - &pdev->dev); - if (ret < 0) - v4l2_err(&csi2->sd, "request csi-intr2 failed: %d\n", - ret); - csi2->irq2 = irq; - } else { - v4l2_err(&csi2->sd, "No found irq csi-intr2\n"); - } - mutex_init(&csi2->lock); ret = csi2_media_init(&csi2->sd); @@ -1115,11 +1140,183 @@ int rkcif_csi2_plat_drv_init(void) return platform_driver_register(&csi2_driver); } -void __exit rkcif_csi2_plat_drv_exit(void) +void rkcif_csi2_plat_drv_exit(void) { platform_driver_unregister(&csi2_driver); } +static const struct csi2_hw_match_data rk1808_csi2_hw_match_data = { + .chip_id = CHIP_RK1808_CSI2, +}; + +static const struct csi2_hw_match_data rk3288_csi2_hw_match_data = { + .chip_id = CHIP_RK3288_CSI2, +}; + +static const struct csi2_hw_match_data rv1126_csi2_hw_match_data = { + .chip_id = CHIP_RV1126_CSI2, +}; + +static const struct csi2_hw_match_data rk3568_csi2_hw_match_data = { + .chip_id = CHIP_RK3568_CSI2, +}; + +static const struct csi2_hw_match_data rk3588_csi2_hw_match_data = { + .chip_id = CHIP_RK3588_CSI2, +}; + +static const struct csi2_hw_match_data rv1106_csi2_hw_match_data = { + .chip_id = CHIP_RV1106_CSI2, +}; + +static const struct csi2_hw_match_data rk3562_csi2_hw_match_data = { + .chip_id = CHIP_RK3562_CSI2, +}; + +static const struct of_device_id csi2_hw_ids[] = { + { + .compatible = "rockchip,rk1808-mipi-csi2-hw", + .data = &rk1808_csi2_hw_match_data, + }, + { + .compatible = "rockchip,rk3288-mipi-csi2-hw", + .data = &rk3288_csi2_hw_match_data, + }, + { + .compatible = "rockchip,rk3568-mipi-csi2-hw", + .data = &rk3568_csi2_hw_match_data, + }, + { + .compatible = "rockchip,rv1126-mipi-csi2-hw", + .data = &rv1126_csi2_hw_match_data, + }, + { + .compatible = "rockchip,rk3588-mipi-csi2-hw", + .data = &rk3588_csi2_hw_match_data, + }, + { + .compatible = "rockchip,rv1106-mipi-csi2-hw", + .data = &rv1106_csi2_hw_match_data, + }, + { + .compatible = "rockchip,rk3562-mipi-csi2-hw", + .data = &rk3588_csi2_hw_match_data, + }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, csi2_hw_ids); + +static int csi2_hw_probe(struct platform_device *pdev) +{ + const struct of_device_id *match; + struct device *dev = &pdev->dev; + struct device_node *node = pdev->dev.of_node; + struct csi2_hw *csi2_hw = NULL; + struct resource *res; + const struct csi2_hw_match_data *data; + int ret, irq; + + dev_info(&pdev->dev, "enter mipi csi2 hw probe!\n"); + match = of_match_node(csi2_hw_ids, node); + if (IS_ERR(match)) + return PTR_ERR(match); + data = match->data; + + csi2_hw = devm_kzalloc(&pdev->dev, sizeof(*csi2_hw), GFP_KERNEL); + if (!csi2_hw) + return -ENOMEM; + + csi2_hw->dev = &pdev->dev; + csi2_hw->match_data = data; + + csi2_hw->dev_name = node->name; + + csi2_hw->clks_num = devm_clk_bulk_get_all(dev, &csi2_hw->clks_bulk); + if (csi2_hw->clks_num < 0) { + csi2_hw->clks_num = 0; + dev_err(dev, "failed to get csi2 clks\n"); + } + + csi2_hw->rsts_bulk = devm_reset_control_array_get_optional_exclusive(dev); + if (IS_ERR(csi2_hw->rsts_bulk)) { + if (PTR_ERR(csi2_hw->rsts_bulk) != -EPROBE_DEFER) + dev_err(dev, "failed to get csi2 reset\n"); + csi2_hw->rsts_bulk = NULL; + } + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + csi2_hw->base = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(csi2_hw->base)) { + resource_size_t offset = res->start; + resource_size_t size = resource_size(res); + + dev_warn(&pdev->dev, "avoid secondary mipi resource check!\n"); + + csi2_hw->base = devm_ioremap(&pdev->dev, offset, size); + if (IS_ERR(csi2_hw->base)) { + dev_err(&pdev->dev, "Failed to ioremap resource\n"); + + return PTR_ERR(csi2_hw->base); + } + } + + irq = platform_get_irq_byname(pdev, "csi-intr1"); + if (irq > 0) { + ret = devm_request_irq(&pdev->dev, irq, + rk_csirx_irq1_handler, 0, + dev_driver_string(&pdev->dev), + &pdev->dev); + if (ret < 0) + dev_err(&pdev->dev, "request csi-intr1 irq failed: %d\n", + ret); + csi2_hw->irq1 = irq; + } else { + dev_err(&pdev->dev, "No found irq csi-intr1\n"); + } + + irq = platform_get_irq_byname(pdev, "csi-intr2"); + if (irq > 0) { + ret = devm_request_irq(&pdev->dev, irq, + rk_csirx_irq2_handler, 0, + dev_driver_string(&pdev->dev), + &pdev->dev); + if (ret < 0) + dev_err(&pdev->dev, "request csi-intr2 failed: %d\n", + ret); + csi2_hw->irq2 = irq; + } else { + dev_err(&pdev->dev, "No found irq csi-intr2\n"); + } + platform_set_drvdata(pdev, csi2_hw); + dev_info(&pdev->dev, "probe success, v4l2_dev:%s!\n", csi2_hw->dev_name); + + return 0; +} + +static int csi2_hw_remove(struct platform_device *pdev) +{ + return 0; +} + +static struct platform_driver csi2_hw_driver = { + .driver = { + .name = DEVICE_NAME_HW, + .of_match_table = csi2_hw_ids, + }, + .probe = csi2_hw_probe, + .remove = csi2_hw_remove, +}; + +int rkcif_csi2_hw_plat_drv_init(void) +{ + return platform_driver_register(&csi2_hw_driver); +} + +void rkcif_csi2_hw_plat_drv_exit(void) +{ + platform_driver_unregister(&csi2_hw_driver); +} + MODULE_DESCRIPTION("Rockchip MIPI CSI2 driver"); MODULE_AUTHOR("Macrofly.xu "); MODULE_LICENSE("GPL"); diff --git a/drivers/media/platform/rockchip/cif/mipi-csi2.h b/drivers/media/platform/rockchip/cif/mipi-csi2.h index 28bc7c8c6fa4..fc21782fbc32 100644 --- a/drivers/media/platform/rockchip/cif/mipi-csi2.h +++ b/drivers/media/platform/rockchip/cif/mipi-csi2.h @@ -8,6 +8,7 @@ #include #include #include +#include #define CSI2_ERR_FSFE_MASK (0xff << 8) #define CSI2_ERR_COUNT_ALL_MASK (0xff) @@ -42,6 +43,7 @@ #define CSIHOST_MAX_ERRINT_COUNT 10 #define DEVICE_NAME "rockchip-mipi-csi2" +#define DEVICE_NAME_HW "rockchip-mipi-csi2-hw" /* CSI Host Registers Define */ #define CSIHOST_N_LANES 0x04 @@ -76,6 +78,8 @@ #define SW_DATATYPE_LS(x) ((x) << 20) #define SW_DATATYPE_LE(x) ((x) << 26) +#define RK_MAX_CSI_HW (6) + /* * add new chip id in tail in time order * by increasing to distinguish csi2 host version @@ -88,6 +92,7 @@ enum rkcsi2_chip_id { CHIP_RV1126_CSI2, CHIP_RK3568_CSI2, CHIP_RK3588_CSI2, + CHIP_RV1106_CSI2, CHIP_RK3562_CSI2, }; @@ -117,6 +122,11 @@ enum host_type_t { struct csi2_match_data { int chip_id; int num_pads; + int num_hw; +}; + +struct csi2_hw_match_data { + int chip_id; }; struct csi2_sensor_info { @@ -155,10 +165,29 @@ struct csi2_dev { int num_sensors; atomic_t frm_sync_seq; struct csi2_err_stats err_list[RK_CSI2_ERR_MAX]; + struct csi2_hw *csi2_hw[RK_MAX_CSI_HW]; int irq1; int irq2; int dsi_input_en; - u32 csi_idx; + struct rkcif_csi_info csi_info; + const char *dev_name; +}; + +struct csi2_hw { + struct device *dev; + struct clk_bulk_data *clks_bulk; + int clks_num; + struct reset_control *rsts_bulk; + struct csi2_dev *csi2; + const struct csi2_hw_match_data *match_data; + + void __iomem *base; + + /* lock to protect all members below */ + struct mutex lock; + + int irq1; + int irq2; const char *dev_name; }; @@ -166,7 +195,9 @@ u32 rkcif_csi2_get_sof(struct csi2_dev *csi2_dev); void rkcif_csi2_set_sof(struct csi2_dev *csi2_dev, u32 seq); void rkcif_csi2_event_inc_sof(struct csi2_dev *csi2_dev); int rkcif_csi2_plat_drv_init(void); -void __exit rkcif_csi2_plat_drv_exit(void); +void rkcif_csi2_plat_drv_exit(void); +int rkcif_csi2_hw_plat_drv_init(void); +void rkcif_csi2_hw_plat_drv_exit(void); int rkcif_csi2_register_notifier(struct notifier_block *nb); int rkcif_csi2_unregister_notifier(struct notifier_block *nb); void rkcif_csi2_event_reset_pipe(struct csi2_dev *csi2_dev, int reset_src); diff --git a/drivers/media/platform/rockchip/cif/subdev-itf.c b/drivers/media/platform/rockchip/cif/subdev-itf.c index 27f83002ca37..9020fff82c63 100644 --- a/drivers/media/platform/rockchip/cif/subdev-itf.c +++ b/drivers/media/platform/rockchip/cif/subdev-itf.c @@ -342,7 +342,10 @@ static long sditf_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg) mode = (struct rkisp_vicap_mode *)arg; memcpy(&priv->mode, mode, sizeof(*mode)); sditf_reinit_mode(priv, &priv->mode); - mode->input.merge_num = cif_dev->sditf_cnt; + if (priv->is_combine_mode) + mode->input.merge_num = cif_dev->sditf_cnt; + else + mode->input.merge_num = 1; mode->input.index = priv->combine_index; return 0; case RKISP_VICAP_CMD_INIT_BUF: @@ -430,6 +433,7 @@ static long sditf_compat_ioctl32(struct v4l2_subdev *sd, static int sditf_channel_enable(struct sditf_priv *priv, int user) { struct rkcif_device *cif_dev = priv->cif_dev; + struct rkmodule_capture_info *capture_info = &cif_dev->channels[0].capture_info; unsigned int ch0 = 0, ch1 = 0, ch2 = 0; unsigned int ctrl_val = 0; unsigned int int_en = 0; @@ -437,11 +441,25 @@ static int sditf_channel_enable(struct sditf_priv *priv, int user) unsigned int offset_y = 0; unsigned int width = priv->cap_info.width; unsigned int height = priv->cap_info.height; + int csi_idx = cif_dev->csi_host_idx; + + if (capture_info->mode == RKMODULE_MULTI_DEV_COMBINE_ONE && + priv->toisp_inf.link_mode == TOISP_UNITE) { + if (capture_info->multi_dev.dev_num != 2 || + capture_info->multi_dev.pixel_offset != RKMOUDLE_UNITE_EXTEND_PIXEL) { + v4l2_err(&cif_dev->v4l2_dev, + "param error of online mode, combine dev num %d, offset %d\n", + capture_info->multi_dev.dev_num, + capture_info->multi_dev.pixel_offset); + return -EINVAL; + } + csi_idx = capture_info->multi_dev.dev_idx[user]; + } if (priv->hdr_cfg.hdr_mode == NO_HDR || priv->hdr_cfg.hdr_mode == HDR_COMPR) { if (cif_dev->inf_id == RKCIF_MIPI_LVDS) - ch0 = cif_dev->csi_host_idx * 4; + ch0 = csi_idx * 4; else ch0 = 24;//dvp ctrl_val = (ch0 << 3) | 0x1; @@ -496,7 +514,10 @@ static int sditf_channel_enable(struct sditf_priv *priv, int user) } } else { if (priv->toisp_inf.link_mode == TOISP_UNITE) { - offset_x = priv->cap_info.width / 2 - RKMOUDLE_UNITE_EXTEND_PIXEL; + if (capture_info->mode == RKMODULE_MULTI_DEV_COMBINE_ONE) + offset_x = 0; + else + offset_x = priv->cap_info.width / 2 - RKMOUDLE_UNITE_EXTEND_PIXEL; width = priv->cap_info.width / 2 + RKMOUDLE_UNITE_EXTEND_PIXEL; } rkcif_write_register(cif_dev, CIF_REG_TOISP1_CTRL, ctrl_val); diff --git a/drivers/media/platform/rockchip/cif/version.h b/drivers/media/platform/rockchip/cif/version.h index 627b4a3a11e5..dbebed0ca0ef 100644 --- a/drivers/media/platform/rockchip/cif/version.h +++ b/drivers/media/platform/rockchip/cif/version.h @@ -67,6 +67,8 @@ *7. add keepint time to csi2 err for resetting *8. mipi supports pdaf/embedded data *9. mipi supports interlaced capture + *v0.2.0 + *1. vicap support combine multi mipi dev to one dev, this function is mainly used for rk3588 */ #define RKCIF_DRIVER_VERSION RKCIF_API_VERSION From a9ed7b93e657b49420dc7c02c3ce9ce810e9b7d3 Mon Sep 17 00:00:00 2001 From: Zefa Chen Date: Wed, 21 Dec 2022 10:19:50 +0800 Subject: [PATCH 3/3] media: rockchip: vicap compatible with rk3588s2 Signed-off-by: Zefa Chen Change-Id: Idd8312275b97b690de378094116d558e85b4cb00 --- drivers/media/platform/rockchip/cif/capture.c | 50 +++++++++++------ .../media/platform/rockchip/cif/cif-scale.c | 4 +- .../media/platform/rockchip/cif/cif-tools.c | 4 +- drivers/media/platform/rockchip/cif/dev.c | 15 +++++- drivers/media/platform/rockchip/cif/dev.h | 3 +- drivers/media/platform/rockchip/cif/hw.c | 54 +++++++++++++++++++ drivers/media/platform/rockchip/cif/hw.h | 1 + 7 files changed, 110 insertions(+), 21 deletions(-) diff --git a/drivers/media/platform/rockchip/cif/capture.c b/drivers/media/platform/rockchip/cif/capture.c index 2b76a5f17c0e..3d5a1d55123c 100644 --- a/drivers/media/platform/rockchip/cif/capture.c +++ b/drivers/media/platform/rockchip/cif/capture.c @@ -847,10 +847,11 @@ static int get_csi_crop_align(const struct cif_input_fmt *fmt_in) } const struct -cif_input_fmt *get_input_fmt(struct v4l2_subdev *sd, struct v4l2_rect *rect, +cif_input_fmt *rkcif_get_input_fmt(struct rkcif_device *dev, struct v4l2_rect *rect, u32 pad_id, struct csi_channel_info *csi_info) { struct v4l2_subdev_format fmt; + struct v4l2_subdev *sd = dev->terminal_sensor.sd; struct rkmodule_channel_info ch_info = {0}; struct rkmodule_capture_info capture_info; int ret; @@ -914,8 +915,22 @@ cif_input_fmt *get_input_fmt(struct v4l2_subdev *sd, struct v4l2_rect *rect, core, ioctl, RKMODULE_GET_CAPTURE_MODE, &capture_info); - if (!ret) + if (!ret) { + if (capture_info.mode == RKMODULE_MULTI_DEV_COMBINE_ONE && + dev->hw_dev->is_rk3588s2) { + for (i = 0; i < capture_info.multi_dev.dev_num; i++) { + if (capture_info.multi_dev.dev_idx[i] == 0) + capture_info.multi_dev.dev_idx[i] = 2; + else if (capture_info.multi_dev.dev_idx[i] == 2) + capture_info.multi_dev.dev_idx[i] = 4; + else if (capture_info.multi_dev.dev_idx[i] == 3) + capture_info.multi_dev.dev_idx[i] = 5; + } + } csi_info->capture_info = capture_info; + } else { + csi_info->capture_info.mode = RKMODULE_CAPTURE_MODE_NONE; + } for (i = 0; i < ARRAY_SIZE(in_fmts); i++) if (fmt.format.code == in_fmts[i].mbus_code && fmt.format.field == in_fmts[i].field) @@ -5362,9 +5377,9 @@ static int rkcif_sanity_check_fmt(struct rkcif_stream *stream, struct v4l2_rect input, *crop; if (dev->terminal_sensor.sd) { - stream->cif_fmt_in = get_input_fmt(dev->terminal_sensor.sd, - &input, stream->id, - &dev->channels[stream->id]); + stream->cif_fmt_in = rkcif_get_input_fmt(dev, + &input, stream->id, + &dev->channels[stream->id]); if (!stream->cif_fmt_in) { v4l2_err(v4l2_dev, "Input fmt is invalid\n"); return -EINVAL; @@ -6146,10 +6161,15 @@ int rkcif_do_start_stream(struct rkcif_stream *stream, unsigned int mode) csi_info.csi_num, RKCIF_MAX_CSI_NUM); goto out; } - for (i = 0; i < csi_info.csi_num; i++) + for (i = 0; i < csi_info.csi_num; i++) { csi_info.csi_idx[i] = dev->channels[0].capture_info.multi_dev.dev_idx[i]; + if (dev->hw_dev->is_rk3588s2) + v4l2_info(v4l2_dev, "rk3588s2 combine mode attach to mipi%d\n", + csi_info.csi_idx[i]); + } } else { csi_info.csi_num = 1; + dev->csi_host_idx = dev->csi_host_idx_def; csi_info.csi_idx[0] = dev->csi_host_idx; } ret = v4l2_subdev_call(dev->active_sensor->sd, @@ -6350,9 +6370,9 @@ int rkcif_set_fmt(struct rkcif_stream *stream, input_rect.height = RKCIF_DEFAULT_HEIGHT; if (dev->terminal_sensor.sd) { - cif_fmt_in = get_input_fmt(dev->terminal_sensor.sd, - &input_rect, stream->id, - channel_info); + cif_fmt_in = rkcif_get_input_fmt(dev, + &input_rect, stream->id, + channel_info); stream->cif_fmt_in = cif_fmt_in; } else { v4l2_err(&stream->cifdev->v4l2_dev, @@ -6720,9 +6740,9 @@ static int rkcif_enum_framesizes(struct file *file, void *prov, input_rect.height = RKCIF_DEFAULT_HEIGHT; if (dev->terminal_sensor.sd) - get_input_fmt(dev->terminal_sensor.sd, - &input_rect, stream->id, - &csi_info); + rkcif_get_input_fmt(dev, + &input_rect, stream->id, + &csi_info); if (dev->hw_dev->adapt_to_usbcamerahal) { fsize->type = V4L2_FRMSIZE_TYPE_DISCRETE; @@ -6801,7 +6821,7 @@ static int rkcif_enum_fmt_vid_cap_mplane(struct file *file, void *priv, return -EINVAL; if (dev->terminal_sensor.sd) { - cif_fmt_in = get_input_fmt(dev->terminal_sensor.sd, + cif_fmt_in = rkcif_get_input_fmt(dev, &input_rect, stream->id, &dev->channels[stream->id]); stream->cif_fmt_in = cif_fmt_in; @@ -7187,8 +7207,8 @@ static long rkcif_ioctl_default(struct file *file, void *fh, break; case RKCIF_CMD_SET_CSI_MEMORY_MODE: if (dev->terminal_sensor.sd) { - in_fmt = get_input_fmt(dev->terminal_sensor.sd, - &rect, 0, &csi_info); + in_fmt = rkcif_get_input_fmt(dev, + &rect, 0, &csi_info); if (in_fmt == NULL) { v4l2_err(&dev->v4l2_dev, "can't get sensor input format\n"); return -EINVAL; diff --git a/drivers/media/platform/rockchip/cif/cif-scale.c b/drivers/media/platform/rockchip/cif/cif-scale.c index 7ea3404258f0..3beede6ee93f 100644 --- a/drivers/media/platform/rockchip/cif/cif-scale.c +++ b/drivers/media/platform/rockchip/cif/cif-scale.c @@ -364,8 +364,8 @@ static int rkcif_scale_enum_framesizes(struct file *file, void *prov, input_rect.height = RKCIF_DEFAULT_HEIGHT; if (terminal_sensor && terminal_sensor->sd) - get_input_fmt(terminal_sensor->sd, - &input_rect, 0, &csi_info); + rkcif_get_input_fmt(dev, + &input_rect, 0, &csi_info); switch (fsize->index) { case SCALE_8TIMES: diff --git a/drivers/media/platform/rockchip/cif/cif-tools.c b/drivers/media/platform/rockchip/cif/cif-tools.c index e3a676c04b4b..60103bf71402 100644 --- a/drivers/media/platform/rockchip/cif/cif-tools.c +++ b/drivers/media/platform/rockchip/cif/cif-tools.c @@ -300,8 +300,8 @@ static int rkcif_tools_enum_framesizes(struct file *file, void *prov, input_rect.height = RKCIF_DEFAULT_HEIGHT; if (terminal_sensor && terminal_sensor->sd) - get_input_fmt(terminal_sensor->sd, - &input_rect, 0, &csi_info); + rkcif_get_input_fmt(dev, + &input_rect, 0, &csi_info); fsize->type = V4L2_FRMSIZE_TYPE_DISCRETE; s->width = input_rect.width; diff --git a/drivers/media/platform/rockchip/cif/dev.c b/drivers/media/platform/rockchip/cif/dev.c index e931dc61389d..6f41ab36a23a 100644 --- a/drivers/media/platform/rockchip/cif/dev.c +++ b/drivers/media/platform/rockchip/cif/dev.c @@ -1998,6 +1998,17 @@ int rkcif_plat_init(struct rkcif_device *cif_dev, struct device_node *node, int cif_dev->csi_host_idx = of_alias_get_id(node, "rkcif_mipi_lvds"); if (cif_dev->csi_host_idx < 0 || cif_dev->csi_host_idx > 5) cif_dev->csi_host_idx = 0; + if (cif_dev->hw_dev->is_rk3588s2) { + if (cif_dev->csi_host_idx == 0) + cif_dev->csi_host_idx = 2; + else if (cif_dev->csi_host_idx == 2) + cif_dev->csi_host_idx = 4; + else if (cif_dev->csi_host_idx == 3) + cif_dev->csi_host_idx = 5; + v4l2_info(&cif_dev->v4l2_dev, "rk3588s2 attach to mipi%d\n", + cif_dev->csi_host_idx); + } + cif_dev->csi_host_idx_def = cif_dev->csi_host_idx; cif_dev->media_dev.dev = dev; v4l2_dev = &cif_dev->v4l2_dev; v4l2_dev->mdev = &cif_dev->media_dev; @@ -2160,7 +2171,9 @@ static int rkcif_plat_probe(struct platform_device *pdev) if (sysfs_create_group(&pdev->dev.kobj, &dev_attr_grp)) return -ENODEV; - rkcif_attach_hw(cif_dev); + ret = rkcif_attach_hw(cif_dev); + if (ret) + return ret; rkcif_parse_dts(cif_dev); diff --git a/drivers/media/platform/rockchip/cif/dev.h b/drivers/media/platform/rockchip/cif/dev.h index c0974a8c7719..b5d4c0315e8c 100644 --- a/drivers/media/platform/rockchip/cif/dev.h +++ b/drivers/media/platform/rockchip/cif/dev.h @@ -845,6 +845,7 @@ struct rkcif_device { struct rkcif_work_struct reset_work; int id_use_cnt; unsigned int csi_host_idx; + unsigned int csi_host_idx_def; unsigned int dvp_sof_in_oneframe; unsigned int wait_line; unsigned int wait_line_bak; @@ -887,7 +888,7 @@ void rkcif_vb_done_tasklet(struct rkcif_stream *stream, struct rkcif_buffer *buf int rkcif_scale_start(struct rkcif_scale_vdev *scale_vdev); const struct -cif_input_fmt *get_input_fmt(struct v4l2_subdev *sd, +cif_input_fmt *rkcif_get_input_fmt(struct rkcif_device *dev, struct v4l2_rect *rect, u32 pad_id, struct csi_channel_info *csi_info); diff --git a/drivers/media/platform/rockchip/cif/hw.c b/drivers/media/platform/rockchip/cif/hw.c index af0f0633e7bb..bf5653961509 100644 --- a/drivers/media/platform/rockchip/cif/hw.c +++ b/drivers/media/platform/rockchip/cif/hw.c @@ -8,6 +8,7 @@ #include #include #include +#include #include #include #include @@ -1252,6 +1253,51 @@ void rkcif_hw_soft_reset(struct rkcif_hw *cif_hw, bool is_rst_iommu) rkcif_iommu_enable(cif_hw); } +static int rkcif_get_efuse_value(struct device_node *np, char *porp_name, + u8 *value) +{ + struct nvmem_cell *cell; + unsigned char *buf; + size_t len; + + cell = of_nvmem_cell_get(np, porp_name); + if (IS_ERR(cell)) + return PTR_ERR(cell); + + buf = (unsigned char *)nvmem_cell_read(cell, &len); + + nvmem_cell_put(cell); + + if (IS_ERR(buf)) + return PTR_ERR(buf); + + *value = buf[0]; + + kfree(buf); + + return 0; +} + +static int rkcif_get_speciand_package_number(struct device_node *np) +{ + u8 spec = 0, package = 0, low = 0, high = 0; + + if (rkcif_get_efuse_value(np, "specification", &spec)) + return -EINVAL; + if (rkcif_get_efuse_value(np, "package_low", &low)) + return -EINVAL; + if (rkcif_get_efuse_value(np, "package_high", &high)) + return -EINVAL; + + package = ((high & 0x1) << 3) | low; + + /* RK3588S */ + if (spec == 0x13) + return package; + + return -EINVAL; +} + static int rkcif_plat_hw_probe(struct platform_device *pdev) { const struct of_device_id *match; @@ -1265,6 +1311,7 @@ static int rkcif_plat_hw_probe(struct platform_device *pdev) int i, ret, irq; bool is_mem_reserved = false; struct notifier_block *notifier; + int package = 0; match = of_match_node(rkcif_plat_of_match, node); if (IS_ERR(match)) @@ -1278,6 +1325,13 @@ static int rkcif_plat_hw_probe(struct platform_device *pdev) dev_set_drvdata(dev, cif_hw); cif_hw->dev = dev; + package = rkcif_get_speciand_package_number(node); + if (package == 0x2) { + cif_hw->is_rk3588s2 = true; + dev_info(dev, "attach rk3588s2\n"); + } else { + cif_hw->is_rk3588s2 = false; + } irq = platform_get_irq(pdev, 0); if (irq < 0) return irq; diff --git a/drivers/media/platform/rockchip/cif/hw.h b/drivers/media/platform/rockchip/cif/hw.h index 56bc785cdd82..4faa9c46e085 100644 --- a/drivers/media/platform/rockchip/cif/hw.h +++ b/drivers/media/platform/rockchip/cif/hw.h @@ -150,6 +150,7 @@ struct rkcif_hw { bool is_dma_contig; bool adapt_to_usbcamerahal; u64 irq_time; + bool is_rk3588s2; }; void rkcif_hw_soft_reset(struct rkcif_hw *cif_hw, bool is_rst_iommu);