From 354a15b789573e034b439cc89b565f2012fd5c71 Mon Sep 17 00:00:00 2001 From: Zefa Chen Date: Sat, 11 Dec 2021 17:18:27 +0800 Subject: [PATCH] phy: rockchip: csi2-dphy: rk3588 dcphy tx/rx combine to one driver Signed-off-by: Zefa Chen Change-Id: I5c28feef615dd4a6b8d7e8ec0514c32625da567b --- .../rockchip/phy-rockchip-csi2-dphy-common.h | 6 + .../phy/rockchip/phy-rockchip-csi2-dphy-hw.c | 264 --------- drivers/phy/rockchip/phy-rockchip-csi2-dphy.c | 202 +++++-- .../phy/rockchip/phy-rockchip-samsung-dcphy.c | 538 ++++++++++++++++-- .../phy/rockchip/phy-rockchip-samsung-dcphy.h | 47 ++ 5 files changed, 705 insertions(+), 352 deletions(-) create mode 100644 drivers/phy/rockchip/phy-rockchip-samsung-dcphy.h diff --git a/drivers/phy/rockchip/phy-rockchip-csi2-dphy-common.h b/drivers/phy/rockchip/phy-rockchip-csi2-dphy-common.h index 3c55ecf548ef..7d78b61215ef 100644 --- a/drivers/phy/rockchip/phy-rockchip-csi2-dphy-common.h +++ b/drivers/phy/rockchip/phy-rockchip-csi2-dphy-common.h @@ -8,6 +8,8 @@ #ifndef _PHY_ROCKCHIP_CSI2_DPHY_COMMON_H_ #define _PHY_ROCKCHIP_CSI2_DPHY_COMMON_H_ +#include + #define PHY_MAX 16 #define MAX_DEV_NAME_LEN 32 @@ -52,15 +54,18 @@ struct csi2_sensor { }; struct csi2_dphy_hw; +struct samsung_mipi_dcphy; struct dphy_drv_data { const char dev_name[MAX_DEV_NAME_LEN]; + enum csi2_dphy_vendor vendor; }; struct csi2_dphy { struct device *dev; struct list_head list; struct csi2_dphy_hw *dphy_hw; + struct samsung_mipi_dcphy *samsung_phy; struct v4l2_async_notifier notifier; struct v4l2_subdev sd; struct mutex mutex; /* lock for updating protection */ @@ -72,6 +77,7 @@ struct csi2_dphy { bool is_streaming; enum csi2_dphy_lane_mode lane_mode; const struct dphy_drv_data *drv_data; + struct rkmodule_csi_dphy_param *dphy_param; }; struct dphy_hw_drv_data { diff --git a/drivers/phy/rockchip/phy-rockchip-csi2-dphy-hw.c b/drivers/phy/rockchip/phy-rockchip-csi2-dphy-hw.c index 2fe84b2d64ef..efb55d22d241 100644 --- a/drivers/phy/rockchip/phy-rockchip-csi2-dphy-hw.c +++ b/drivers/phy/rockchip/phy-rockchip-csi2-dphy-hw.c @@ -41,9 +41,6 @@ #define GRF_CSI2PHY_SEL_SPLIT_0_1 (0x0) #define GRF_CSI2PHY_SEL_SPLIT_2_3 BIT(0) -/*RK3588 DCPHY GRF REG OFFSET */ -#define GRF_DCPHY_CON0 (0x0) - /* PHY REG OFFSET */ #define CSI2_DPHY_CTRL_INVALID_OFFSET (0xffff) #define CSI2_DPHY_CTRL_PWRCTL \ @@ -71,27 +68,6 @@ #define CSI2_DPHY_PATH1_MODE_SEL (0x84C) #define CSI2_DPHY_PATH1_LVDS_MODE_SEL (0x880) -#define CSI2_DCPHY_CLK_WR_THS_SETTLE (0x030) -#define CSI2_DCPHY_LANE0_WR_THS_SETTLE (0x130) -#define CSI2_DCPHY_LANE0_WR_ERR_SOT_SYNC (0x134) -#define CSI2_DCPHY_LANE1_WR_THS_SETTLE (0x230) -#define CSI2_DCPHY_LANE1_WR_ERR_SOT_SYNC (0x234) -#define CSI2_DCPHY_LANE2_WR_THS_SETTLE (0x330) -#define CSI2_DCPHY_LANE2_WR_ERR_SOT_SYNC (0x334) -#define CSI2_DCPHY_LANE3_WR_THS_SETTLE (0x430) -#define CSI2_DCPHY_LANE3_WR_ERR_SOT_SYNC (0x434) -#define CSI2_DCPHY_CLK_LANE_ENABLE (0x000) -#define CSI2_DCPHY_DATA_LANE0_ENABLE (0x100) -#define CSI2_DCPHY_DATA_LANE1_ENABLE (0x200) -#define CSI2_DCPHY_DATA_LANE2_ENABLE (0x300) -#define CSI2_DCPHY_DATA_LANE3_ENABLE (0x400) - -#define CSI2_DCPHY_S0C_GNR_CON1 (0x004) -#define CSI2_DCPHY_COMBO_S0D0_GNR_CON1 (0x104) -#define CSI2_DCPHY_COMBO_S0D1_GNR_CON1 (0x204) -#define CSI2_DCPHY_COMBO_S0D2_GNR_CON1 (0x304) -#define CSI2_DCPHY_S0D3_GNR_CON1 (0x304) - /* PHY REG BIT DEFINE */ #define CSI2_DPHY_LANE_MODE_FULL (0x4) #define CSI2_DPHY_LANE_MODE_SPLIT (0x2) @@ -410,32 +386,6 @@ static const struct csi2dphy_reg rk3588_csi2dphy_regs[] = { [CSI2PHY_CLK1_LANE_ENABLE] = CSI2PHY_REG(CSI2_DPHY_CLK1_LANE_EN), }; -static const struct grf_reg rk3588_grf_dcphy_regs[] = { - [GRF_CPHY_MODE] = GRF_REG(GRF_DCPHY_CON0, 9, 0), -}; - -static const struct csi2dphy_reg rk3588_csi2dcphy_regs[] = { - [CSI2PHY_CLK_THS_SETTLE] = CSI2PHY_REG(CSI2_DCPHY_CLK_WR_THS_SETTLE), - [CSI2PHY_LANE0_THS_SETTLE] = CSI2PHY_REG(CSI2_DCPHY_LANE0_WR_THS_SETTLE), - [CSI2PHY_LANE0_ERR_SOT_SYNC] = CSI2PHY_REG(CSI2_DCPHY_LANE0_WR_ERR_SOT_SYNC), - [CSI2PHY_LANE1_THS_SETTLE] = CSI2PHY_REG(CSI2_DCPHY_LANE1_WR_THS_SETTLE), - [CSI2PHY_LANE1_ERR_SOT_SYNC] = CSI2PHY_REG(CSI2_DCPHY_LANE1_WR_ERR_SOT_SYNC), - [CSI2PHY_LANE2_THS_SETTLE] = CSI2PHY_REG(CSI2_DCPHY_LANE2_WR_THS_SETTLE), - [CSI2PHY_LANE2_ERR_SOT_SYNC] = CSI2PHY_REG(CSI2_DCPHY_LANE2_WR_ERR_SOT_SYNC), - [CSI2PHY_LANE3_THS_SETTLE] = CSI2PHY_REG(CSI2_DCPHY_LANE3_WR_THS_SETTLE), - [CSI2PHY_LANE3_ERR_SOT_SYNC] = CSI2PHY_REG(CSI2_DCPHY_LANE3_WR_ERR_SOT_SYNC), - [CSI2PHY_CLK_LANE_ENABLE] = CSI2PHY_REG(CSI2_DCPHY_CLK_LANE_ENABLE), - [CSI2PHY_DATA_LANE0_ENABLE] = CSI2PHY_REG(CSI2_DCPHY_DATA_LANE0_ENABLE), - [CSI2PHY_DATA_LANE1_ENABLE] = CSI2PHY_REG(CSI2_DCPHY_DATA_LANE1_ENABLE), - [CSI2PHY_DATA_LANE2_ENABLE] = CSI2PHY_REG(CSI2_DCPHY_DATA_LANE2_ENABLE), - [CSI2PHY_DATA_LANE3_ENABLE] = CSI2PHY_REG(CSI2_DCPHY_DATA_LANE3_ENABLE), - [CSI2PHY_S0C_GNR_CON1] = CSI2PHY_REG(CSI2_DCPHY_S0C_GNR_CON1), - [CSI2PHY_COMBO_S0D0_GNR_CON1] = CSI2PHY_REG(CSI2_DCPHY_COMBO_S0D0_GNR_CON1), - [CSI2PHY_COMBO_S0D1_GNR_CON1] = CSI2PHY_REG(CSI2_DCPHY_COMBO_S0D1_GNR_CON1), - [CSI2PHY_COMBO_S0D2_GNR_CON1] = CSI2PHY_REG(CSI2_DCPHY_COMBO_S0D2_GNR_CON1), - [CSI2PHY_S0D3_GNR_CON1] = CSI2PHY_REG(CSI2_DCPHY_S0D3_GNR_CON1), -}; - static const struct grf_reg rv1106_grf_dphy_regs[] = { [GRF_DPHY_CSI2PHY_FORCERXMODE] = GRF_REG(GRF_VI_CSIPHY_CON5, 4, 0), [GRF_DPHY_CSI2PHY_CLKLANE_EN] = GRF_REG(GRF_VI_CSIPHY_CON5, 1, 8), @@ -480,37 +430,6 @@ static const struct hsfreq_range rk3568_csi2_dphy_hw_hsfreq_ranges[] = { {2199, 0x3c}, {2399, 0x41}, {2499, 0x46} }; -/* These tables must be sorted by .range_h ascending. */ -static const struct hsfreq_range rk3588_csi2_dcphy_d_hw_hsfreq_ranges[] = { - { 80, 0x105}, { 100, 0x106}, { 120, 0x107}, { 140, 0x108}, - { 160, 0x109}, { 180, 0x10a}, { 200, 0x10b}, { 220, 0x10c}, - { 240, 0x10d}, { 270, 0x10e}, { 290, 0x10f}, { 310, 0x110}, - { 330, 0x111}, { 350, 0x112}, { 370, 0x113}, { 390, 0x114}, - { 410, 0x115}, { 430, 0x116}, { 450, 0x117}, { 470, 0x118}, - { 490, 0x119}, { 510, 0x11a}, { 540, 0x11b}, { 560, 0x11c}, - { 580, 0x11d}, { 600, 0x11e}, { 620, 0x11f}, { 640, 0x120}, - { 660, 0x121}, { 680, 0x122}, { 700, 0x123}, { 720, 0x124}, - { 740, 0x125}, { 760, 0x126}, { 790, 0x127}, { 810, 0x128}, - { 830, 0x129}, { 850, 0x12a}, { 870, 0x12b}, { 890, 0x12c}, - { 910, 0x12d}, { 930, 0x12e}, { 950, 0x12f}, { 970, 0x130}, - { 990, 0x131}, {1010, 0x132}, {1030, 0x133}, {1060, 0x134}, - {1080, 0x135}, {1100, 0x136}, {1120, 0x137}, {1140, 0x138}, - {1160, 0x139}, {1180, 0x13a}, {1200, 0x13b}, {1220, 0x13c}, - {1240, 0x13d}, {1260, 0x13e}, {1280, 0x13f}, {1310, 0x140}, - {1330, 0x141}, {1350, 0x142}, {1370, 0x143}, {1390, 0x144}, - {1410, 0x145}, {1430, 0x146}, {1450, 0x147}, {1470, 0x148}, - {1490, 0x149}, {1580, 0x007}, {1740, 0x008}, {1910, 0x009}, - {2070, 0x00a}, {2240, 0x00b}, {2410, 0x00c}, {2570, 0x00d}, - {2740, 0x00e}, {2910, 0x00f}, {3070, 0x010}, {3240, 0x011}, - {3410, 0x012}, {3570, 0x013}, {3740, 0x014}, {3890, 0x015}, - {4070, 0x016}, {4240, 0x017}, {4400, 0x018}, {4500, 0x019}, -}; - -/* These tables must be sorted by .range_h ascending. */ -static const struct hsfreq_range rk3588_csi2_dcphy_c_hw_hsfreq_ranges[] = { - { 500, 0x102}, { 990, 0x002}, { 2500, 0x001}, -}; - static struct v4l2_subdev *get_remote_sensor(struct v4l2_subdev *sd) { struct media_pad *local, *remote; @@ -863,167 +782,6 @@ static int csi2_dphy_hw_stream_off(struct csi2_dphy *dphy, return 0; } -static int csi_dcphy_wait_lane_prepare(struct csi2_dphy_hw *hw, int index) -{ - int count = 0; - u32 val = 0; - - read_csi2_dphy_reg(hw, index, &val); - while (!(val & BIT(1))) { - usleep_range(10, 20); - read_csi2_dphy_reg(hw, index, &val); - count++; - if (count > 2000) - return -EINVAL; - } - return 0; -} - -static int csi2_dcphy_hw_stream_on(struct csi2_dphy *dphy, - struct v4l2_subdev *sd) -{ - struct v4l2_subdev *sensor_sd = get_remote_sensor(sd); - struct csi2_sensor *sensor = sd_to_sensor(dphy, sensor_sd); - struct csi2_dphy_hw *hw = dphy->dphy_hw; - const struct dphy_hw_drv_data *drv_data = hw->drv_data; - const struct hsfreq_range *hsfreq_ranges = drv_data->hsfreq_ranges; - int num_hsfreq_ranges = drv_data->num_hsfreq_ranges; - int i, hsfreq = 0; - u32 sot_sync = 0; - - if (sensor->mbus.type == V4L2_MBUS_CSI2_DPHY) { - hsfreq_ranges = drv_data->hsfreq_ranges; - num_hsfreq_ranges = drv_data->num_hsfreq_ranges; - sot_sync = 0x03; - } else if (sensor->mbus.type == V4L2_MBUS_CSI2_CPHY) { - hsfreq_ranges = drv_data->hsfreq_ranges_cphy; - num_hsfreq_ranges = drv_data->num_hsfreq_ranges_cphy; - sot_sync = 0x32; - } - - mutex_lock(&hw->mutex); - if (sensor->mbus.type == V4L2_MBUS_CSI2_CPHY) - write_grf_reg(hw, GRF_CPHY_MODE, 0x9); - - if (hw->rsts_bulk) - reset_control_assert(hw->rsts_bulk); - - /*clk settle fix to 0x301*/ - if (sensor->mbus.type == V4L2_MBUS_CSI2_DPHY) { - write_csi2_dphy_reg(hw, CSI2PHY_CLK_THS_SETTLE, 0x301); - write_csi2_dphy_reg(hw, CSI2PHY_S0C_GNR_CON1, 0x1450); - write_csi2_dphy_reg(hw, CSI2PHY_COMBO_S0D0_GNR_CON1, 0x1450); - write_csi2_dphy_reg(hw, CSI2PHY_COMBO_S0D1_GNR_CON1, 0x1450); - write_csi2_dphy_reg(hw, CSI2PHY_COMBO_S0D2_GNR_CON1, 0x1450); - write_csi2_dphy_reg(hw, CSI2PHY_S0D3_GNR_CON1, 0x1450); - } - /* set data lane */ - for (i = 0; i < num_hsfreq_ranges; i++) { - if (hsfreq_ranges[i].range_h >= dphy->data_rate_mbps) { - hsfreq = hsfreq_ranges[i].cfg_bit; - break; - } - } - - if (i == num_hsfreq_ranges) { - i = num_hsfreq_ranges - 1; - dev_warn(dphy->dev, "data rate: %lld mbps, max support %d mbps", - dphy->data_rate_mbps, hsfreq_ranges[i].range_h + 1); - hsfreq = hsfreq_ranges[i].cfg_bit; - } - if (sensor->lanes > 0x00) { - write_csi2_dphy_reg_mask(hw, CSI2PHY_LANE0_THS_SETTLE, hsfreq, 0x1ff); - write_csi2_dphy_reg_mask(hw, CSI2PHY_LANE0_ERR_SOT_SYNC, sot_sync, 0xff); - } - if (sensor->lanes > 0x01) { - write_csi2_dphy_reg_mask(hw, CSI2PHY_LANE1_THS_SETTLE, hsfreq, 0x1ff); - write_csi2_dphy_reg_mask(hw, CSI2PHY_LANE1_ERR_SOT_SYNC, sot_sync, 0xff); - } - if (sensor->lanes > 0x02) { - write_csi2_dphy_reg_mask(hw, CSI2PHY_LANE2_THS_SETTLE, hsfreq, 0x1ff); - write_csi2_dphy_reg_mask(hw, CSI2PHY_LANE2_ERR_SOT_SYNC, sot_sync, 0xff); - } - if (sensor->lanes > 0x03) { - write_csi2_dphy_reg_mask(hw, CSI2PHY_LANE3_THS_SETTLE, hsfreq, 0x1ff); - write_csi2_dphy_reg_mask(hw, CSI2PHY_LANE3_ERR_SOT_SYNC, sot_sync, 0xff); - } - - if (sensor->mbus.type == V4L2_MBUS_CSI2_DPHY) - write_csi2_dphy_reg(hw, CSI2PHY_CLK_LANE_ENABLE, BIT(0)); - - if (sensor->lanes > 0x00) - write_csi2_dphy_reg(hw, CSI2PHY_DATA_LANE0_ENABLE, BIT(0)); - if (sensor->lanes > 0x01) - write_csi2_dphy_reg(hw, CSI2PHY_DATA_LANE1_ENABLE, BIT(0)); - if (sensor->lanes > 0x02) - write_csi2_dphy_reg(hw, CSI2PHY_DATA_LANE2_ENABLE, BIT(0)); - if (sensor->lanes > 0x03) - write_csi2_dphy_reg(hw, CSI2PHY_DATA_LANE3_ENABLE, BIT(0)); - - /*wait for clk lane ready*/ - if (sensor->mbus.type == V4L2_MBUS_CSI2_DPHY) - if (csi_dcphy_wait_lane_prepare(hw, CSI2PHY_CLK_LANE_ENABLE)) - goto out_streamon; - - /*wait for data lane ready*/ - if (sensor->lanes > 0x00) - if (csi_dcphy_wait_lane_prepare(hw, CSI2PHY_DATA_LANE0_ENABLE)) - goto out_streamon; - if (sensor->lanes > 0x01) - if (csi_dcphy_wait_lane_prepare(hw, CSI2PHY_DATA_LANE1_ENABLE)) - goto out_streamon; - if (sensor->lanes > 0x02) - if (csi_dcphy_wait_lane_prepare(hw, CSI2PHY_DATA_LANE2_ENABLE)) - goto out_streamon; - if (sensor->lanes > 0x03) - if (csi_dcphy_wait_lane_prepare(hw, CSI2PHY_DATA_LANE3_ENABLE)) - goto out_streamon; - - if (hw->rsts_bulk) - reset_control_deassert(hw->rsts_bulk); - atomic_inc(&hw->stream_cnt); - - mutex_unlock(&hw->mutex); - - return 0; -out_streamon: - if (hw->rsts_bulk) - reset_control_deassert(hw->rsts_bulk); - mutex_unlock(&hw->mutex); - dev_err(dphy->dev, "stream on error\n"); - return -EINVAL; - -} - -static int csi2_dcphy_hw_stream_off(struct csi2_dphy *dphy, - struct v4l2_subdev *sd) -{ - struct csi2_dphy_hw *hw = dphy->dphy_hw; - struct v4l2_subdev *sensor_sd = get_remote_sensor(sd); - struct csi2_sensor *sensor = sd_to_sensor(dphy, sensor_sd); - - if (atomic_dec_return(&hw->stream_cnt)) - return 0; - - mutex_lock(&hw->mutex); - if (sensor->mbus.type == V4L2_MBUS_CSI2_DPHY) - write_csi2_dphy_reg(hw, CSI2PHY_CLK_LANE_ENABLE, 0); - if (sensor->lanes > 0x00) - write_csi2_dphy_reg(hw, CSI2PHY_DATA_LANE0_ENABLE, 0); - if (sensor->lanes > 0x01) - write_csi2_dphy_reg(hw, CSI2PHY_DATA_LANE1_ENABLE, 0); - if (sensor->lanes > 0x02) - write_csi2_dphy_reg(hw, CSI2PHY_DATA_LANE2_ENABLE, 0); - if (sensor->lanes > 0x03) - write_csi2_dphy_reg(hw, CSI2PHY_DATA_LANE3_ENABLE, 0); - - usleep_range(500, 1000); - - mutex_unlock(&hw->mutex); - - return 0; -} - static void rk3568_csi2_dphy_hw_individual_init(struct csi2_dphy_hw *hw) { hw->grf_regs = rk3568_grf_dphy_regs; @@ -1034,11 +792,6 @@ static void rk3588_csi2_dphy_hw_individual_init(struct csi2_dphy_hw *hw) hw->grf_regs = rk3588_grf_dphy_regs; } -static void rk3588_csi2_dcphy_hw_individual_init(struct csi2_dphy_hw *hw) -{ - hw->grf_regs = rk3588_grf_dcphy_regs; -} - static void rv1106_csi2_dphy_hw_individual_init(struct csi2_dphy_hw *hw) { hw->grf_regs = rv1106_grf_dphy_regs; @@ -1066,19 +819,6 @@ static const struct dphy_hw_drv_data rk3588_csi2_dphy_hw_drv_data = { .stream_off = csi2_dphy_hw_stream_off, }; -static const struct dphy_hw_drv_data rk3588_csi2_dcphy_hw_drv_data = { - .hsfreq_ranges = rk3588_csi2_dcphy_d_hw_hsfreq_ranges, - .num_hsfreq_ranges = ARRAY_SIZE(rk3588_csi2_dcphy_d_hw_hsfreq_ranges), - .hsfreq_ranges_cphy = rk3588_csi2_dcphy_c_hw_hsfreq_ranges, - .num_hsfreq_ranges_cphy = ARRAY_SIZE(rk3588_csi2_dcphy_c_hw_hsfreq_ranges), - .csi2dphy_regs = rk3588_csi2dcphy_regs, - .grf_regs = rk3588_grf_dcphy_regs, - .individual_init = rk3588_csi2_dcphy_hw_individual_init, - .chip_id = CHIP_ID_RK3588_DCPHY, - .stream_on = csi2_dcphy_hw_stream_on, - .stream_off = csi2_dcphy_hw_stream_off, -}; - static const struct dphy_hw_drv_data rv1106_csi2_dphy_hw_drv_data = { .hsfreq_ranges = rk3568_csi2_dphy_hw_hsfreq_ranges, .num_hsfreq_ranges = ARRAY_SIZE(rk3568_csi2_dphy_hw_hsfreq_ranges), @@ -1099,10 +839,6 @@ static const struct of_device_id rockchip_csi2_dphy_hw_match_id[] = { .compatible = "rockchip,rk3588-csi2-dphy-hw", .data = &rk3588_csi2_dphy_hw_drv_data, }, - { - .compatible = "rockchip,rk3588-csi2-dcphy-hw", - .data = &rk3588_csi2_dcphy_hw_drv_data, - }, { .compatible = "rockchip,rv1106-csi2-dphy-hw", .data = &rv1106_csi2_dphy_hw_drv_data, diff --git a/drivers/phy/rockchip/phy-rockchip-csi2-dphy.c b/drivers/phy/rockchip/phy-rockchip-csi2-dphy.c index 3302940bf996..aa41c71b096c 100644 --- a/drivers/phy/rockchip/phy-rockchip-csi2-dphy.c +++ b/drivers/phy/rockchip/phy-rockchip-csi2-dphy.c @@ -21,8 +21,9 @@ #include #include #include +#include #include "phy-rockchip-csi2-dphy-common.h" -#include +#include "phy-rockchip-samsung-dcphy.h" struct sensor_async_subdev { struct v4l2_async_subdev asd; @@ -127,44 +128,58 @@ static int csi2_dphy_update_sensor_mbus(struct v4l2_subdev *sd) default: return -EINVAL; } - 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; + 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; + } } + } 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_err(dphy->dev, "%s fail to get dphy param, used default value\n", + __func__); + ret = 0; } - } else { - ret = 0; } return ret; } @@ -173,6 +188,7 @@ 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; if (dphy->is_streaming) @@ -184,8 +200,13 @@ static int csi2_dphy_s_stream_start(struct v4l2_subdev *sd) csi2_dphy_update_sensor_mbus(sd); - if (hw->stream_on) - hw->stream_on(dphy, 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); + } dphy->is_streaming = true; @@ -196,12 +217,18 @@ 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; if (!dphy->is_streaming) return 0; - if (hw->stream_off) - hw->stream_off(dphy, sd); + 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); + } dphy->is_streaming = false; @@ -273,9 +300,15 @@ static __maybe_unused int csi2_dphy_runtime_suspend(struct device *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 (hw) - clk_bulk_disable_unprepare(hw->num_clks, hw->clks_bulk); + 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); + } return 0; } @@ -286,13 +319,19 @@ static __maybe_unused int csi2_dphy_runtime_resume(struct device *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 (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; + 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; + } } } @@ -503,6 +542,47 @@ 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; @@ -591,14 +671,28 @@ static int rockchip_csi2_dphy_detach_hw(struct csi2_dphy *dphy) static struct dphy_drv_data rk3568_dphy_drv_data = { .dev_name = "csi2dphy", + .vendor = PHY_VENDOR_INNO, }; 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 rv1106_dphy_drv_data = { .dev_name = "csi2dphy", + .vendor = PHY_VENDOR_INNO, }; static const struct of_device_id rockchip_csi2_dphy_match_id[] = { @@ -640,7 +734,12 @@ static int rockchip_csi2_dphy_probe(struct platform_device *pdev) 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; - ret = rockchip_csi2_dphy_attach_hw(csi2dphy); + 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", @@ -670,7 +769,10 @@ static int rockchip_csi2_dphy_probe(struct platform_device *pdev) detach_hw: mutex_destroy(&csi2dphy->mutex); - rockchip_csi2_dphy_detach_hw(csi2dphy); + if (csi2dphy->drv_data->vendor == PHY_VENDOR_SAMSUNG) + rockchip_csi2_dphy_detach_samsung_phy(csi2dphy); + else + rockchip_csi2_dphy_detach_hw(csi2dphy); return 0; } diff --git a/drivers/phy/rockchip/phy-rockchip-samsung-dcphy.c b/drivers/phy/rockchip/phy-rockchip-samsung-dcphy.c index 1d5db69eed44..4798989b6253 100644 --- a/drivers/phy/rockchip/phy-rockchip-samsung-dcphy.c +++ b/drivers/phy/rockchip/phy-rockchip-samsung-dcphy.c @@ -16,6 +16,12 @@ #include #include #include +#include +#include +#include +#include +#include "phy-rockchip-csi2-dphy-common.h" +#include "phy-rockchip-samsung-dcphy.h" #define UPDATE(x, h, l) (((x) << (l)) & GENMASK((h), (l))) #define HIWORD_UPDATE(v, h, l) (((v) << (l)) | (GENMASK((h), (l)) << 16)) @@ -150,6 +156,66 @@ #define MAX_DPHY_BW 4500000L #define MAX_CPHY_BW 2000000L +#define RX_CLK_THS_SETTLE (0xb30) +#define RX_LANE0_THS_SETTLE (0xC30) +#define RX_LANE0_ERR_SOT_SYNC (0xC34) +#define RX_LANE1_THS_SETTLE (0xD30) +#define RX_LANE1_ERR_SOT_SYNC (0xD34) +#define RX_LANE2_THS_SETTLE (0xE30) +#define RX_LANE2_ERR_SOT_SYNC (0xE34) +#define RX_LANE3_THS_SETTLE (0xF30) +#define RX_LANE3_ERR_SOT_SYNC (0xF34) +#define RX_CLK_LANE_ENABLE (0xB00) +#define RX_DATA_LANE0_ENABLE (0xC00) +#define RX_DATA_LANE1_ENABLE (0xD00) +#define RX_DATA_LANE2_ENABLE (0xE00) +#define RX_DATA_LANE3_ENABLE (0xF00) + +#define RX_S0C_GNR_CON1 (0xB04) +#define RX_S0C_ANA_CON1 (0xB0c) +#define RX_S0C_ANA_CON2 (0xB10) +#define RX_S0C_ANA_CON3 (0xB14) +#define RX_COMBO_S0D0_GNR_CON1 (0xC04) +#define RX_COMBO_S0D0_ANA_CON1 (0xC0c) +#define RX_COMBO_S0D0_ANA_CON2 (0xC10) +#define RX_COMBO_S0D0_ANA_CON3 (0xC14) +#define RX_COMBO_S0D0_ANA_CON6 (0xC20) +#define RX_COMBO_S0D0_ANA_CON7 (0xC24) +#define RX_COMBO_S0D0_DESKEW_CON0 (0xC40) +#define RX_COMBO_S0D0_DESKEW_CON2 (0xC48) +#define RX_COMBO_S0D0_DESKEW_CON4 (0xC50) +#define RX_COMBO_S0D0_CRC_CON1 (0xC64) +#define RX_COMBO_S0D0_CRC_CON2 (0xC68) +#define RX_COMBO_S0D1_GNR_CON1 (0xD04) +#define RX_COMBO_S0D1_ANA_CON1 (0xD0c) +#define RX_COMBO_S0D1_ANA_CON2 (0xD10) +#define RX_COMBO_S0D1_ANA_CON3 (0xD14) +#define RX_COMBO_S0D1_ANA_CON6 (0xD20) +#define RX_COMBO_S0D1_ANA_CON7 (0xD24) +#define RX_COMBO_S0D1_DESKEW_CON0 (0xD40) +#define RX_COMBO_S0D1_DESKEW_CON2 (0xD48) +#define RX_COMBO_S0D1_DESKEW_CON4 (0xD50) +#define RX_COMBO_S0D1_CRC_CON1 (0xD64) +#define RX_COMBO_S0D1_CRC_CON2 (0xD68) +#define RX_COMBO_S0D2_GNR_CON1 (0xE04) +#define RX_COMBO_S0D2_ANA_CON1 (0xE0c) +#define RX_COMBO_S0D2_ANA_CON2 (0xE10) +#define RX_COMBO_S0D2_ANA_CON3 (0xE14) +#define RX_COMBO_S0D2_ANA_CON6 (0xE20) +#define RX_COMBO_S0D2_ANA_CON7 (0xE24) +#define RX_COMBO_S0D2_DESKEW_CON0 (0xE40) +#define RX_COMBO_S0D2_DESKEW_CON2 (0xE48) +#define RX_COMBO_S0D2_DESKEW_CON4 (0xE50) +#define RX_COMBO_S0D2_CRC_CON1 (0xE64) +#define RX_COMBO_S0D2_CRC_CON2 (0xE68) +#define RX_S0D3_GNR_CON1 (0xF04) +#define RX_S0D3_ANA_CON1 (0xF0c) +#define RX_S0D3_ANA_CON2 (0xF10) +#define RX_S0D3_ANA_CON3 (0xF14) +#define RX_S0D3_DESKEW_CON0 (0xF40) +#define RX_S0D3_DESKEW_CON2 (0xF48) +#define RX_S0D3_DESKEW_CON4 (0xF50) + struct samsung_mipi_dphy_timing { unsigned int max_lane_mbps; u8 clk_prepare; @@ -174,32 +240,6 @@ struct samsung_mipi_cphy_timing { u8 settle_3; }; -struct samsung_mipi_dcphy { - struct device *dev; - struct clk *ref_clk; - struct clk *pclk; - struct regmap *regmap; - struct regmap *grf_regmap; - struct reset_control *phy_rst; - struct reset_control *apb_rst; - struct reset_control *grf_apb_rst; - bool c_option; - - unsigned int lanes; - - struct { - unsigned long long rate; - u8 prediv; - u16 fbdiv; - long dsm; - u8 scaler; - - bool ssc_en; - u8 mfr; - u8 mrr; - } pll; -}; - static const struct samsung_mipi_dphy_timing samsung_mipi_dphy_timing_table[] = { {6500, 32, 117, 31, 28, 30, 56, 27, 24, 44, 37}, @@ -1194,11 +1234,58 @@ struct samsung_mipi_cphy_timing samsung_mipi_cphy_timing_table[] = { { 80, 1, 50, 25, 2, 0, 2 }, }; +struct hsfreq_range { + u32 range_h; + u16 cfg_bit; +}; +/* These tables must be sorted by .range_h ascending. */ +static const struct hsfreq_range samsung_dphy_rx_hsfreq_ranges[] = { + { 80, 0x105}, { 100, 0x106}, { 120, 0x107}, { 140, 0x108}, + { 160, 0x109}, { 180, 0x10a}, { 200, 0x10b}, { 220, 0x10c}, + { 240, 0x10d}, { 270, 0x10e}, { 290, 0x10f}, { 310, 0x110}, + { 330, 0x111}, { 350, 0x112}, { 370, 0x113}, { 390, 0x114}, + { 410, 0x115}, { 430, 0x116}, { 450, 0x117}, { 470, 0x118}, + { 490, 0x119}, { 510, 0x11a}, { 540, 0x11b}, { 560, 0x11c}, + { 580, 0x11d}, { 600, 0x11e}, { 620, 0x11f}, { 640, 0x120}, + { 660, 0x121}, { 680, 0x122}, { 700, 0x123}, { 720, 0x124}, + { 740, 0x125}, { 760, 0x126}, { 790, 0x127}, { 810, 0x128}, + { 830, 0x129}, { 850, 0x12a}, { 870, 0x12b}, { 890, 0x12c}, + { 910, 0x12d}, { 930, 0x12e}, { 950, 0x12f}, { 970, 0x130}, + { 990, 0x131}, {1010, 0x132}, {1030, 0x133}, {1060, 0x134}, + {1080, 0x135}, {1100, 0x136}, {1120, 0x137}, {1140, 0x138}, + {1160, 0x139}, {1180, 0x13a}, {1200, 0x13b}, {1220, 0x13c}, + {1240, 0x13d}, {1260, 0x13e}, {1280, 0x13f}, {1310, 0x140}, + {1330, 0x141}, {1350, 0x142}, {1370, 0x143}, {1390, 0x144}, + {1410, 0x145}, {1430, 0x146}, {1450, 0x147}, {1470, 0x148}, + {1490, 0x149}, {1580, 0x007}, {1740, 0x008}, {1910, 0x009}, + {2070, 0x00a}, {2240, 0x00b}, {2410, 0x00c}, {2570, 0x00d}, + {2740, 0x00e}, {2910, 0x00f}, {3070, 0x010}, {3240, 0x011}, + {3410, 0x012}, {3570, 0x013}, {3740, 0x014}, {3890, 0x015}, + {4070, 0x016}, {4240, 0x017}, {4400, 0x018}, {4500, 0x019}, +}; + +/* These tables must be sorted by .range_h ascending. */ +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) { + struct csi2_dphy *csi_dphy = samsung->dphy_dev[0]; + u32 bias_con2 = 0x3223; + + if (csi_dphy && + csi_dphy->dphy_param->lp_vol_ref != 3 && + csi_dphy->dphy_param->lp_vol_ref < 0x7) { + bias_con2 &= 0xfffffff8; + bias_con2 |= csi_dphy->dphy_param->lp_vol_ref; + dev_info(samsung->dev, + "rx change lp_vol_ref to %d, it may cause tx exception\n", + csi_dphy->dphy_param->lp_vol_ref); + } regmap_write(samsung->regmap, BIAS_CON0, 0x0010); regmap_write(samsung->regmap, BIAS_CON1, 0x0110); - regmap_write(samsung->regmap, BIAS_CON2, 0x3223); + regmap_write(samsung->regmap, BIAS_CON2, bias_con2); /* default output voltage select: * dphy: 400mv @@ -1612,7 +1699,7 @@ samsung_mipi_dcphy_hs_vreg_amp_configure(struct samsung_mipi_dcphy *samsung) static void samsung_mipi_dphy_power_on(struct samsung_mipi_dcphy *samsung) { - reset_control_assert(samsung->phy_rst); + reset_control_assert(samsung->m_phy_rst); samsung_mipi_dcphy_bias_block_enable(samsung); samsung_mipi_dcphy_pll_configure(samsung); @@ -1621,7 +1708,7 @@ static void samsung_mipi_dphy_power_on(struct samsung_mipi_dcphy *samsung) samsung_mipi_dcphy_pll_enable(samsung); samsung_mipi_dphy_lane_enable(samsung); - reset_control_deassert(samsung->phy_rst); + reset_control_deassert(samsung->m_phy_rst); /* The TSKEWCAL maximum is 100 µsec * at initial calibration. @@ -1632,7 +1719,7 @@ static void samsung_mipi_dphy_power_on(struct samsung_mipi_dcphy *samsung) 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->phy_rst); + reset_control_assert(samsung->m_phy_rst); samsung_mipi_dcphy_bias_block_enable(samsung); samsung_mipi_dcphy_hs_vreg_amp_configure(samsung); @@ -1641,7 +1728,7 @@ static void samsung_mipi_cphy_power_on(struct samsung_mipi_dcphy *samsung) samsung_mipi_dcphy_pll_enable(samsung); samsung_mipi_cphy_lane_enable(samsung); - reset_control_deassert(samsung->phy_rst); + reset_control_deassert(samsung->m_phy_rst); } static int samsung_mipi_dcphy_power_on(struct phy *phy) @@ -1796,6 +1883,369 @@ static int samsung_mipi_dcphy_configure(struct phy *phy, return 0; } +static struct v4l2_subdev *get_remote_sensor(struct v4l2_subdev *sd) +{ + struct media_pad *local, *remote; + struct media_entity *sensor_me; + + local = &sd->entity.pads[CSI2_DPHY_RX_PAD_SINK]; + remote = media_entity_remote_pad(local); + if (!remote) { + v4l2_warn(sd, "No link between dphy and sensor\n"); + return NULL; + } + + sensor_me = media_entity_remote_pad(local)->entity; + return media_entity_to_v4l2_subdev(sensor_me); +} + +static struct csi2_sensor *sd_to_sensor(struct csi2_dphy *dphy, + struct v4l2_subdev *sd) +{ + int i; + + for (i = 0; i < dphy->num_sensors; ++i) + if (dphy->sensors[i].sd == sd) + return &dphy->sensors[i]; + + return NULL; +} + +static void samsung_dcphy_rx_config_settle(struct csi2_dphy *dphy, + struct csi2_sensor *sensor) +{ + struct samsung_mipi_dcphy *samsung = dphy->samsung_phy; + const struct hsfreq_range *hsfreq_ranges = NULL; + int num_hsfreq_ranges = 0; + int i, hsfreq = 0; + u32 sot_sync = 0; + + if (sensor->mbus.type == V4L2_MBUS_CSI2_DPHY) { + hsfreq_ranges = samsung_dphy_rx_hsfreq_ranges; + num_hsfreq_ranges = ARRAY_SIZE(samsung_dphy_rx_hsfreq_ranges); + sot_sync = 0x03; + } else if (sensor->mbus.type == V4L2_MBUS_CSI2_CPHY) { + hsfreq_ranges = samsung_cphy_rx_hsfreq_ranges; + num_hsfreq_ranges = ARRAY_SIZE(samsung_cphy_rx_hsfreq_ranges); + sot_sync = 0x32; + } else { + dev_err(dphy->dev, "mbus type %d is not support", + sensor->mbus.type); + return; + } + /* set data lane */ + for (i = 0; i < num_hsfreq_ranges; i++) { + if (hsfreq_ranges[i].range_h >= dphy->data_rate_mbps) { + hsfreq = hsfreq_ranges[i].cfg_bit; + break; + } + } + + if (i == num_hsfreq_ranges) { + i = num_hsfreq_ranges - 1; + dev_warn(dphy->dev, "data rate: %lld mbps, max support %d mbps", + dphy->data_rate_mbps, hsfreq_ranges[i].range_h + 1); + hsfreq = hsfreq_ranges[i].cfg_bit; + } + /*clk settle fix to 0x301*/ + if (sensor->mbus.type == V4L2_MBUS_CSI2_DPHY) + regmap_write(samsung->regmap, RX_CLK_THS_SETTLE, 0x301); + + if (sensor->lanes > 0x00) { + regmap_update_bits(samsung->regmap, RX_LANE0_THS_SETTLE, 0x1ff, hsfreq); + regmap_update_bits(samsung->regmap, RX_LANE0_ERR_SOT_SYNC, 0xff, sot_sync); + } + if (sensor->lanes > 0x01) { + regmap_update_bits(samsung->regmap, RX_LANE1_THS_SETTLE, 0x1ff, hsfreq); + regmap_update_bits(samsung->regmap, RX_LANE1_ERR_SOT_SYNC, 0xff, sot_sync); + } + if (sensor->lanes > 0x02) { + regmap_update_bits(samsung->regmap, RX_LANE2_THS_SETTLE, 0x1ff, hsfreq); + regmap_update_bits(samsung->regmap, RX_LANE2_ERR_SOT_SYNC, 0xff, sot_sync); + } + if (sensor->lanes > 0x03) { + regmap_update_bits(samsung->regmap, RX_LANE3_THS_SETTLE, 0x1ff, hsfreq); + regmap_update_bits(samsung->regmap, RX_LANE3_ERR_SOT_SYNC, 0xff, sot_sync); + } +} + +static int samsung_dcphy_rx_config_common(struct csi2_dphy *dphy, + struct csi2_sensor *sensor) +{ + struct samsung_mipi_dcphy *samsung = dphy->samsung_phy; + u32 dlysel = 0; + int i = 0; + + if (sensor->mbus.type == V4L2_MBUS_CSI2_DPHY) { + if (dphy->data_rate_mbps < 1500) + dlysel = 0; + else if (dphy->data_rate_mbps < 2000) + dlysel = 3 << 8; + else if (dphy->data_rate_mbps < 3000) + dlysel = 2 << 8; + else if (dphy->data_rate_mbps < 4000) + dlysel = 1 << 8; + else if (dphy->data_rate_mbps < 6500) + dlysel = 0; + if (dphy->dphy_param->clk_hs_term_sel > 0x7) { + dev_err(dphy->dev, "clk_hs_term_sel error param %d\n", + dphy->dphy_param->clk_hs_term_sel); + return -EINVAL; + } + for (i = 0; i < sensor->lanes; i++) { + if (dphy->dphy_param->data_hs_term_sel[i] > 0x7) { + dev_err(dphy->dev, "data_hs_term_sel[%d] error param %d\n", + i, + dphy->dphy_param->data_hs_term_sel[i]); + return -EINVAL; + } + if (dphy->dphy_param->lp_hys_sw[i] > 0x3) { + dev_err(dphy->dev, "lp_hys_sw[%d] error param %d\n", + i, + dphy->dphy_param->lp_hys_sw[i]); + return -EINVAL; + } + if (dphy->dphy_param->lp_escclk_pol_sel[i] > 0x1) { + dev_err(dphy->dev, "lp_escclk_pol_sel[%d] error param %d\n", + i, + dphy->dphy_param->lp_escclk_pol_sel[i]); + return -EINVAL; + } + if (dphy->dphy_param->skew_data_cal_clk[i] > 0x1f) { + dev_err(dphy->dev, "skew_data_cal_clk[%d] error param %d\n", + i, + dphy->dphy_param->skew_data_cal_clk[i]); + return -EINVAL; + } + } + regmap_write(samsung->regmap, RX_S0C_GNR_CON1, 0x1450); + regmap_write(samsung->regmap, RX_S0C_ANA_CON1, 0x8000); + regmap_write(samsung->regmap, RX_S0C_ANA_CON2, dphy->dphy_param->clk_hs_term_sel); + regmap_write(samsung->regmap, RX_S0C_ANA_CON3, 0x0600); + if (sensor->lanes > 0x00) { + regmap_write(samsung->regmap, RX_COMBO_S0D0_GNR_CON1, 0x1450); + regmap_write(samsung->regmap, RX_COMBO_S0D0_ANA_CON1, 0x8000); + regmap_write(samsung->regmap, RX_COMBO_S0D0_ANA_CON2, dlysel | + dphy->dphy_param->data_hs_term_sel[0]); + regmap_write(samsung->regmap, RX_COMBO_S0D0_ANA_CON3, 0x0600 | + (dphy->dphy_param->lp_hys_sw[0] << 4) | + (dphy->dphy_param->lp_escclk_pol_sel[0] << 11)); + regmap_write(samsung->regmap, RX_COMBO_S0D0_ANA_CON7, 0x40); + regmap_write(samsung->regmap, RX_COMBO_S0D0_DESKEW_CON2, + dphy->dphy_param->skew_data_cal_clk[0]); + } + if (sensor->lanes > 0x01) { + regmap_write(samsung->regmap, RX_COMBO_S0D1_GNR_CON1, 0x1450); + regmap_write(samsung->regmap, RX_COMBO_S0D1_ANA_CON1, 0x8000); + regmap_write(samsung->regmap, RX_COMBO_S0D1_ANA_CON2, dlysel | + dphy->dphy_param->data_hs_term_sel[1]); + regmap_write(samsung->regmap, RX_COMBO_S0D1_ANA_CON3, 0x0600 | + (dphy->dphy_param->lp_hys_sw[1] << 4) | + (dphy->dphy_param->lp_escclk_pol_sel[1] << 11)); + regmap_write(samsung->regmap, RX_COMBO_S0D1_ANA_CON7, 0x40); + regmap_write(samsung->regmap, RX_COMBO_S0D1_DESKEW_CON2, + dphy->dphy_param->skew_data_cal_clk[1]); + } + if (sensor->lanes > 0x02) { + regmap_write(samsung->regmap, RX_COMBO_S0D2_GNR_CON1, 0x1450); + regmap_write(samsung->regmap, RX_COMBO_S0D2_ANA_CON1, 0x8000); + regmap_write(samsung->regmap, RX_COMBO_S0D2_ANA_CON2, dlysel | + dphy->dphy_param->data_hs_term_sel[2]); + regmap_write(samsung->regmap, RX_COMBO_S0D2_ANA_CON3, 0x0600 | + (dphy->dphy_param->lp_hys_sw[2] << 4) | + (dphy->dphy_param->lp_escclk_pol_sel[2] << 11)); + regmap_write(samsung->regmap, RX_COMBO_S0D2_ANA_CON7, 0x40); + regmap_write(samsung->regmap, RX_COMBO_S0D2_DESKEW_CON2, + dphy->dphy_param->skew_data_cal_clk[2]); + } + if (sensor->lanes > 0x03) { + regmap_write(samsung->regmap, RX_S0D3_GNR_CON1, 0x1450); + regmap_write(samsung->regmap, RX_S0D3_ANA_CON1, 0x8000); + regmap_write(samsung->regmap, RX_S0D3_ANA_CON2, dlysel | + dphy->dphy_param->data_hs_term_sel[3]); + regmap_write(samsung->regmap, RX_S0D3_ANA_CON3, 0x0600 | + (dphy->dphy_param->lp_hys_sw[3] << 4) | + (dphy->dphy_param->lp_escclk_pol_sel[3] << 11)); + regmap_write(samsung->regmap, RX_S0D3_DESKEW_CON2, + dphy->dphy_param->skew_data_cal_clk[3]); + } + } else { + if (sensor->lanes > 0x00) { + regmap_write(samsung->regmap, RX_COMBO_S0D0_GNR_CON1, 0x1450); + regmap_write(samsung->regmap, RX_COMBO_S0D0_ANA_CON1, 0x8000); + regmap_write(samsung->regmap, RX_COMBO_S0D0_ANA_CON2, 0x5); + regmap_write(samsung->regmap, RX_COMBO_S0D0_ANA_CON3, 0x600); + regmap_write(samsung->regmap, RX_COMBO_S0D0_ANA_CON6, 0x608); + regmap_write(samsung->regmap, RX_COMBO_S0D0_ANA_CON7, 0x40); + regmap_write(samsung->regmap, RX_COMBO_S0D0_CRC_CON1, 0x1500); + regmap_write(samsung->regmap, RX_COMBO_S0D0_CRC_CON2, 0x30); + } + if (sensor->lanes > 0x01) { + regmap_write(samsung->regmap, RX_COMBO_S0D1_GNR_CON1, 0x1450); + regmap_write(samsung->regmap, RX_COMBO_S0D1_ANA_CON1, 0x8000); + regmap_write(samsung->regmap, RX_COMBO_S0D1_ANA_CON2, 0x5); + regmap_write(samsung->regmap, RX_COMBO_S0D1_ANA_CON3, 0x600); + regmap_write(samsung->regmap, RX_COMBO_S0D1_ANA_CON6, 0x608); + regmap_write(samsung->regmap, RX_COMBO_S0D1_ANA_CON7, 0x40); + regmap_write(samsung->regmap, RX_COMBO_S0D1_CRC_CON1, 0x1500); + regmap_write(samsung->regmap, RX_COMBO_S0D1_CRC_CON2, 0x30); + } + if (sensor->lanes > 0x02) { + regmap_write(samsung->regmap, RX_COMBO_S0D2_GNR_CON1, 0x1450); + regmap_write(samsung->regmap, RX_COMBO_S0D2_ANA_CON1, 0x8000); + regmap_write(samsung->regmap, RX_COMBO_S0D2_ANA_CON2, 0x5); + regmap_write(samsung->regmap, RX_COMBO_S0D2_ANA_CON3, 0x600); + regmap_write(samsung->regmap, RX_COMBO_S0D2_ANA_CON6, 0x608); + regmap_write(samsung->regmap, RX_COMBO_S0D2_ANA_CON7, 0x40); + regmap_write(samsung->regmap, RX_COMBO_S0D2_CRC_CON1, 0x1500); + regmap_write(samsung->regmap, RX_COMBO_S0D2_CRC_CON2, 0x30); + } + } + return 0; +} + +static int samsung_dcphy_rx_lane_enable(struct csi2_dphy *dphy, + struct csi2_sensor *sensor) +{ + struct samsung_mipi_dcphy *samsung = dphy->samsung_phy; + u32 sts; + int ret = 0; + + if (sensor->mbus.type == V4L2_MBUS_CSI2_DPHY) + regmap_update_bits(samsung->regmap, RX_CLK_LANE_ENABLE, PHY_ENABLE, PHY_ENABLE); + + if (sensor->lanes > 0x00) + regmap_update_bits(samsung->regmap, RX_DATA_LANE0_ENABLE, PHY_ENABLE, PHY_ENABLE); + if (sensor->lanes > 0x01) + regmap_update_bits(samsung->regmap, RX_DATA_LANE1_ENABLE, PHY_ENABLE, PHY_ENABLE); + if (sensor->lanes > 0x02) + regmap_update_bits(samsung->regmap, RX_DATA_LANE2_ENABLE, PHY_ENABLE, PHY_ENABLE); + if (sensor->lanes > 0x03) + regmap_update_bits(samsung->regmap, RX_DATA_LANE3_ENABLE, PHY_ENABLE, PHY_ENABLE); + + /*wait for clk lane ready*/ + if (sensor->mbus.type == V4L2_MBUS_CSI2_DPHY) { + ret = regmap_read_poll_timeout(samsung->regmap, RX_CLK_LANE_ENABLE, + sts, (sts & PHY_READY), 200, 4000); + if (ret < 0) { + dev_err(samsung->dev, "phy rx clk lane is not locked\n"); + return -EINVAL; + } + } + + /*wait for data lane ready*/ + if (sensor->lanes > 0x00) { + ret = regmap_read_poll_timeout(samsung->regmap, RX_DATA_LANE0_ENABLE, + sts, (sts & PHY_READY), 200, 2000); + if (ret < 0) { + dev_err(samsung->dev, "phy rx data lane 0 is not locked\n"); + return -EINVAL; + } + } + if (sensor->lanes > 0x01) { + ret = regmap_read_poll_timeout(samsung->regmap, RX_DATA_LANE1_ENABLE, + sts, (sts & PHY_READY), 200, 2000); + if (ret < 0) { + dev_err(samsung->dev, "phy rx data lane 1 is not locked\n"); + return -EINVAL; + } + } + if (sensor->lanes > 0x02) { + ret = regmap_read_poll_timeout(samsung->regmap, RX_DATA_LANE2_ENABLE, + sts, (sts & PHY_READY), 200, 2000); + if (ret < 0) { + dev_err(samsung->dev, "phy rx data lane 2 is not locked\n"); + return -EINVAL; + } + } + + if (sensor->lanes > 0x03) { + ret = regmap_read_poll_timeout(samsung->regmap, RX_DATA_LANE3_ENABLE, + sts, (sts & PHY_READY), 200, 2000); + if (ret < 0) { + dev_err(samsung->dev, "phy rx data lane 3 is not locked\n"); + return -EINVAL; + } + } + return 0; +} + +static int samsung_dcphy_rx_stream_on(struct csi2_dphy *dphy, + struct v4l2_subdev *sd) +{ + struct v4l2_subdev *sensor_sd = get_remote_sensor(sd); + struct csi2_sensor *sensor = sd_to_sensor(dphy, sensor_sd); + struct samsung_mipi_dcphy *samsung = dphy->samsung_phy; + int ret = 0; + + mutex_lock(&samsung->mutex); + if (sensor->mbus.type == V4L2_MBUS_CSI2_CPHY) + regmap_write(samsung->grf_regmap, MIPI_DCPHY_GRF_CON0, S_CPHY_MODE); + + if (samsung->s_phy_rst) + reset_control_assert(samsung->s_phy_rst); + + samsung_mipi_dcphy_bias_block_enable(samsung); + ret = samsung_dcphy_rx_config_common(dphy, sensor); + if (ret) + goto out_streamon; + samsung_dcphy_rx_config_settle(dphy, sensor); + + ret = samsung_dcphy_rx_lane_enable(dphy, sensor); + if (ret) + goto out_streamon; + + if (samsung->s_phy_rst) + reset_control_deassert(samsung->s_phy_rst); + + atomic_inc(&samsung->stream_cnt); + mutex_unlock(&samsung->mutex); + + return 0; +out_streamon: + if (samsung->s_phy_rst) + reset_control_deassert(samsung->s_phy_rst); + mutex_unlock(&samsung->mutex); + dev_err(dphy->dev, "stream on error\n"); + return -EINVAL; + +} + +static int samsung_dcphy_rx_stream_off(struct csi2_dphy *dphy, + struct v4l2_subdev *sd) +{ + struct samsung_mipi_dcphy *samsung = dphy->samsung_phy; + struct v4l2_subdev *sensor_sd = get_remote_sensor(sd); + struct csi2_sensor *sensor = sd_to_sensor(dphy, sensor_sd); + + if (atomic_dec_return(&samsung->stream_cnt)) + return 0; + + mutex_lock(&samsung->mutex); + if (samsung->s_phy_rst) + reset_control_assert(samsung->s_phy_rst); + + if (sensor->mbus.type == V4L2_MBUS_CSI2_DPHY) + regmap_update_bits(samsung->regmap, RX_CLK_LANE_ENABLE, PHY_ENABLE, 0); + + if (sensor->lanes > 0x00) + regmap_update_bits(samsung->regmap, RX_DATA_LANE0_ENABLE, PHY_ENABLE, 0); + if (sensor->lanes > 0x01) + regmap_update_bits(samsung->regmap, RX_DATA_LANE1_ENABLE, PHY_ENABLE, 0); + if (sensor->lanes > 0x02) + regmap_update_bits(samsung->regmap, RX_DATA_LANE2_ENABLE, PHY_ENABLE, 0); + if (sensor->lanes > 0x03) + regmap_update_bits(samsung->regmap, RX_DATA_LANE3_ENABLE, PHY_ENABLE, 0); + + if (samsung->s_phy_rst) + reset_control_deassert(samsung->s_phy_rst); + usleep_range(500, 1000); + + mutex_unlock(&samsung->mutex); + + return 0; +} + static int samsung_mipi_dcphy_init(struct phy *phy) { struct samsung_mipi_dcphy *samsung = phy_get_drvdata(phy); @@ -1824,11 +2274,11 @@ static const struct phy_ops samsung_mipi_dcphy_ops = { }; static const struct regmap_config samsung_mipi_dcphy_regmap_config = { - .name = "dcphy_tx", + .name = "dcphy", .reg_bits = 32, .val_bits = 32, .reg_stride = 4, - .max_register = 0x0b00, + .max_register = 0x10000, }; static int samsung_mipi_dcphy_probe(struct platform_device *pdev) @@ -1880,10 +2330,16 @@ static int samsung_mipi_dcphy_probe(struct platform_device *pdev) return PTR_ERR(samsung->pclk); } - samsung->phy_rst = devm_reset_control_get(dev, "phy"); - if (IS_ERR(samsung->phy_rst)) { - dev_err(dev, "failed to get system phy_rst control\n"); - return PTR_ERR(samsung->phy_rst); + samsung->m_phy_rst = devm_reset_control_get(dev, "m_phy"); + if (IS_ERR(samsung->m_phy_rst)) { + dev_err(dev, "failed to get system m_phy_rst control\n"); + return PTR_ERR(samsung->m_phy_rst); + } + + samsung->s_phy_rst = devm_reset_control_get(dev, "s_phy"); + if (IS_ERR(samsung->s_phy_rst)) { + dev_err(dev, "failed to get system s_phy_rst control\n"); + return PTR_ERR(samsung->s_phy_rst); } samsung->apb_rst = devm_reset_control_get(dev, "apb"); @@ -1912,6 +2368,9 @@ static int samsung_mipi_dcphy_probe(struct platform_device *pdev) return PTR_ERR(phy_provider); } + samsung->stream_on = samsung_dcphy_rx_stream_on; + samsung->stream_off = samsung_dcphy_rx_stream_off; + mutex_init(&samsung->mutex); pm_runtime_enable(dev); return 0; @@ -1922,6 +2381,7 @@ static int samsung_mipi_dcphy_remove(struct platform_device *pdev) struct samsung_mipi_dcphy *samsung = platform_get_drvdata(pdev); pm_runtime_disable(samsung->dev); + mutex_destroy(&samsung->mutex); return 0; } @@ -1952,7 +2412,9 @@ static const struct dev_pm_ops samsung_mipi_dcphy_pm_ops = { }; static const struct of_device_id samsung_mipi_dcphy_of_match[] = { - { .compatible = "rockchip,rk3588-mipi-dcphy", }, + { + .compatible = "rockchip,rk3588-mipi-dcphy", + }, {} }; MODULE_DEVICE_TABLE(of, samsung_mipi_dcphy_of_match); diff --git a/drivers/phy/rockchip/phy-rockchip-samsung-dcphy.h b/drivers/phy/rockchip/phy-rockchip-samsung-dcphy.h new file mode 100644 index 000000000000..2c04aa3b6e05 --- /dev/null +++ b/drivers/phy/rockchip/phy-rockchip-samsung-dcphy.h @@ -0,0 +1,47 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Rockchip Samsung mipi dcphy driver + * + * Copyright (C) 2020 Rockchip Electronics Co., Ltd. + */ + +#ifndef _PHY_ROCKCHIP_SAMSUNG_DCPHY_H_ +#define _PHY_ROCKCHIP_SAMSUNG_DCPHY_H_ + +#define MAX_NUM_CSI2_DPHY (0x2) + +struct samsung_mipi_dcphy { + struct device *dev; + struct clk *ref_clk; + struct clk *pclk; + struct regmap *regmap; + struct regmap *grf_regmap; + struct reset_control *m_phy_rst; + struct reset_control *s_phy_rst; + struct reset_control *apb_rst; + struct reset_control *grf_apb_rst; + struct mutex mutex; + struct csi2_dphy *dphy_dev[MAX_NUM_CSI2_DPHY]; + atomic_t stream_cnt; + int dphy_dev_num; + bool c_option; + + unsigned int lanes; + + struct { + unsigned long long rate; + u8 prediv; + u16 fbdiv; + long dsm; + u8 scaler; + + bool ssc_en; + u8 mfr; + u8 mrr; + } pll; + + int (*stream_on)(struct csi2_dphy *dphy, struct v4l2_subdev *sd); + int (*stream_off)(struct csi2_dphy *dphy, struct v4l2_subdev *sd); +}; + +#endif