diff options
author | Hu Kejun <william.hu@rock-chips.com> | 2018-04-09 16:08:45 +0800 |
---|---|---|
committer | Tao Huang <huangtao@rock-chips.com> | 2018-04-11 18:30:37 +0800 |
commit | 440f7f5fde341a2a40bb508588279dea068fc617 (patch) | |
tree | b542014541dd786ef1f1c84b38ce48b8a81976bf | |
parent | c16d640f8e7d1d23946b4d6b4f0fcd364afed765 (diff) |
media: rockchip: phy: Support for RK3326
Change-Id: I76d076a110a773a9c1c24742564699900476a8d9
Signed-off-by: Hu Kejun <william.hu@rock-chips.com>
-rw-r--r-- | Documentation/devicetree/bindings/media/rockchip-mipi-dphy.txt | 1 | ||||
-rw-r--r-- | drivers/media/platform/rockchip/isp1/mipi_dphy_sy.c | 231 |
2 files changed, 189 insertions, 43 deletions
diff --git a/Documentation/devicetree/bindings/media/rockchip-mipi-dphy.txt b/Documentation/devicetree/bindings/media/rockchip-mipi-dphy.txt index 55c01726782e..bd8b03eb0a16 100644 --- a/Documentation/devicetree/bindings/media/rockchip-mipi-dphy.txt +++ b/Documentation/devicetree/bindings/media/rockchip-mipi-dphy.txt @@ -4,6 +4,7 @@ Rockchip SoC MIPI RX D-PHY Required properties: - compatible: value should be one of the following "rockchip,rk3288-mipi-dphy" + "rockchip,rk3326-mipi-dphy" "rockchip,rk3399-mipi-dphy" - clocks : list of clock specifiers, corresponding to entries in clock-names property; diff --git a/drivers/media/platform/rockchip/isp1/mipi_dphy_sy.c b/drivers/media/platform/rockchip/isp1/mipi_dphy_sy.c index d39f6a5e756d..72b1876cdd03 100644 --- a/drivers/media/platform/rockchip/isp1/mipi_dphy_sy.c +++ b/drivers/media/platform/rockchip/isp1/mipi_dphy_sy.c @@ -55,6 +55,9 @@ #define RK3288_GRF_IO_VSEL 0x0380 #define RK3288_GRF_SOC_CON15 0x03a4 +#define RK3326_GRF_IO_VSEL_OFFSET 0x0180 +#define RK3326_GRF_PD_VI_CON_OFFSET 0x0430 + #define RK3399_GRF_SOC_CON9 0x6224 #define RK3399_GRF_SOC_CON21 0x6254 #define RK3399_GRF_SOC_CON22 0x6258 @@ -70,6 +73,16 @@ #define LANE3_HS_RX_CONTROL 0x94 #define HS_RX_DATA_LANES_THS_SETTLE_CONTROL 0x75 +/* LOW POWER MODE SET */ +#define MIPI_CSI_DPHY_CTRL_LANE_ENABLE_OFFSET 0x00 +#define MIPI_CSI_DPHY_CTRL_DATALANE_ENABLE_OFFSET_BIT 2 +#define MIPI_CSI_DPHY_CTRL_CLKLANE_ENABLE_OFFSET_BIT 6 +#define MIPI_CSI_DPHY_CTRL_PWRCTL_OFFSET 0x04 +#define MIPI_CSI_DPHY_CTRL_DIG_RST_OFFSET 0x80 + +/* Configure the count time of the THS-SETTLE by protocol. */ +#define MIPI_CSI_DPHY_LANEX_THS_SETTLE_OFFSET 0x00 + /* * CSI HOST */ @@ -87,6 +100,12 @@ #define HIWORD_UPDATE(val, mask, shift) \ ((val) << (shift) | (mask) << ((shift) + 16)) +/* csi phy */ +#define write_csiphy_reg(addr, val) \ + writel(val, addr + csihost_base_addr) +#define read_csiphy_reg(addr) \ + readl(addr + csihost_base_addr) + enum mipi_dphy_sy_pads { MIPI_DPHY_SY_PAD_SINK = 0, MIPI_DPHY_SY_PAD_SOURCE, @@ -122,11 +141,28 @@ enum dphy_reg_id { GRF_CON_ISP_DPHY_SEL, GRF_DSI_CSI_TESTBUS_SEL, GRF_DVP_V18SEL, + /* rk3326 only */ + GRF_DPHY_CSIPHY_FORCERXMODE, + GRF_DPHY_CSIPHY_CLKLANE_EN, + GRF_DPHY_CSIPHY_DATALANE_EN, /* below is for rk3399 only */ GRF_DPHY_RX0_CLK_INV_SEL, GRF_DPHY_RX1_CLK_INV_SEL, }; +enum mipi_dphy_ctl_type { + MIPI_DPHY_CTL_GRF_ONLY = 0, + MIPI_DPHY_CTL_CSI_HOST +}; + +enum mipi_dphy_lane { + MIPI_DPHY_LANE_CLOCK = 0, + MIPI_DPHY_LANE_DATA0, + MIPI_DPHY_LANE_DATA1, + MIPI_DPHY_LANE_DATA2, + MIPI_DPHY_LANE_DATA3 +}; + struct dphy_reg { u32 offset; u32 mask; @@ -136,34 +172,6 @@ struct dphy_reg { #define PHY_REG(_offset, _width, _shift) \ { .offset = _offset, .mask = BIT(_width) - 1, .shift = _shift, } -static const struct dphy_reg rk3399_grf_dphy_regs[] = { - [GRF_DPHY_RX0_TURNREQUEST] = PHY_REG(RK3399_GRF_SOC_CON9, 4, 0), - [GRF_DPHY_RX0_CLK_INV_SEL] = PHY_REG(RK3399_GRF_SOC_CON9, 1, 10), - [GRF_DPHY_RX1_CLK_INV_SEL] = PHY_REG(RK3399_GRF_SOC_CON9, 1, 11), - [GRF_DPHY_RX0_ENABLE] = PHY_REG(RK3399_GRF_SOC_CON21, 4, 0), - [GRF_DPHY_RX0_FORCERXMODE] = PHY_REG(RK3399_GRF_SOC_CON21, 4, 4), - [GRF_DPHY_RX0_FORCETXSTOPMODE] = PHY_REG(RK3399_GRF_SOC_CON21, 4, 8), - [GRF_DPHY_RX0_TURNDISABLE] = PHY_REG(RK3399_GRF_SOC_CON21, 4, 12), - [GRF_DPHY_TX0_FORCERXMODE] = PHY_REG(RK3399_GRF_SOC_CON22, 4, 0), - [GRF_DPHY_TX0_FORCETXSTOPMODE] = PHY_REG(RK3399_GRF_SOC_CON22, 4, 4), - [GRF_DPHY_TX0_TURNDISABLE] = PHY_REG(RK3399_GRF_SOC_CON22, 4, 8), - [GRF_DPHY_TX0_TURNREQUEST] = PHY_REG(RK3399_GRF_SOC_CON22, 4, 12), - [GRF_DPHY_TX1RX1_ENABLE] = PHY_REG(RK3399_GRF_SOC_CON23, 4, 0), - [GRF_DPHY_TX1RX1_FORCERXMODE] = PHY_REG(RK3399_GRF_SOC_CON23, 4, 4), - [GRF_DPHY_TX1RX1_FORCETXSTOPMODE] = PHY_REG(RK3399_GRF_SOC_CON23, 4, 8), - [GRF_DPHY_TX1RX1_TURNDISABLE] = PHY_REG(RK3399_GRF_SOC_CON23, 4, 12), - [GRF_DPHY_TX1RX1_TURNREQUEST] = PHY_REG(RK3399_GRF_SOC_CON24, 4, 0), - [GRF_DPHY_RX1_SRC_SEL] = PHY_REG(RK3399_GRF_SOC_CON24, 1, 4), - [GRF_DPHY_TX1RX1_BASEDIR] = PHY_REG(RK3399_GRF_SOC_CON24, 1, 5), - [GRF_DPHY_TX1RX1_ENABLECLK] = PHY_REG(RK3399_GRF_SOC_CON24, 1, 6), - [GRF_DPHY_TX1RX1_MASTERSLAVEZ] = PHY_REG(RK3399_GRF_SOC_CON24, 1, 7), - [GRF_DPHY_RX0_TESTDIN] = PHY_REG(RK3399_GRF_SOC_CON25, 8, 0), - [GRF_DPHY_RX0_TESTEN] = PHY_REG(RK3399_GRF_SOC_CON25, 1, 8), - [GRF_DPHY_RX0_TESTCLK] = PHY_REG(RK3399_GRF_SOC_CON25, 1, 9), - [GRF_DPHY_RX0_TESTCLR] = PHY_REG(RK3399_GRF_SOC_CON25, 1, 10), - [GRF_DPHY_RX0_TESTDOUT] = PHY_REG(RK3399_GRF_SOC_STATUS1, 8, 0), -}; - static const struct dphy_reg rk3288_grf_dphy_regs[] = { [GRF_CON_DISABLE_ISP] = PHY_REG(RK3288_GRF_SOC_CON6, 1, 0), [GRF_CON_ISP_DPHY_SEL] = PHY_REG(RK3288_GRF_SOC_CON6, 1, 1), @@ -194,6 +202,41 @@ static const struct dphy_reg rk3288_grf_dphy_regs[] = { [GRF_DPHY_RX0_TESTDOUT] = PHY_REG(RK3288_GRF_SOC_STATUS21, 8, 0), }; +static const struct dphy_reg rk3326_grf_dphy_regs[] = { + [GRF_DVP_V18SEL] = PHY_REG(RK3326_GRF_IO_VSEL_OFFSET, 1, 4), + [GRF_DPHY_CSIPHY_FORCERXMODE] = PHY_REG(RK3326_GRF_PD_VI_CON_OFFSET, 4, 0), + [GRF_DPHY_CSIPHY_CLKLANE_EN] = PHY_REG(RK3326_GRF_PD_VI_CON_OFFSET, 1, 8), + [GRF_DPHY_CSIPHY_DATALANE_EN] = PHY_REG(RK3326_GRF_PD_VI_CON_OFFSET, 4, 4), +}; + +static const struct dphy_reg rk3399_grf_dphy_regs[] = { + [GRF_DPHY_RX0_TURNREQUEST] = PHY_REG(RK3399_GRF_SOC_CON9, 4, 0), + [GRF_DPHY_RX0_CLK_INV_SEL] = PHY_REG(RK3399_GRF_SOC_CON9, 1, 10), + [GRF_DPHY_RX1_CLK_INV_SEL] = PHY_REG(RK3399_GRF_SOC_CON9, 1, 11), + [GRF_DPHY_RX0_ENABLE] = PHY_REG(RK3399_GRF_SOC_CON21, 4, 0), + [GRF_DPHY_RX0_FORCERXMODE] = PHY_REG(RK3399_GRF_SOC_CON21, 4, 4), + [GRF_DPHY_RX0_FORCETXSTOPMODE] = PHY_REG(RK3399_GRF_SOC_CON21, 4, 8), + [GRF_DPHY_RX0_TURNDISABLE] = PHY_REG(RK3399_GRF_SOC_CON21, 4, 12), + [GRF_DPHY_TX0_FORCERXMODE] = PHY_REG(RK3399_GRF_SOC_CON22, 4, 0), + [GRF_DPHY_TX0_FORCETXSTOPMODE] = PHY_REG(RK3399_GRF_SOC_CON22, 4, 4), + [GRF_DPHY_TX0_TURNDISABLE] = PHY_REG(RK3399_GRF_SOC_CON22, 4, 8), + [GRF_DPHY_TX0_TURNREQUEST] = PHY_REG(RK3399_GRF_SOC_CON22, 4, 12), + [GRF_DPHY_TX1RX1_ENABLE] = PHY_REG(RK3399_GRF_SOC_CON23, 4, 0), + [GRF_DPHY_TX1RX1_FORCERXMODE] = PHY_REG(RK3399_GRF_SOC_CON23, 4, 4), + [GRF_DPHY_TX1RX1_FORCETXSTOPMODE] = PHY_REG(RK3399_GRF_SOC_CON23, 4, 8), + [GRF_DPHY_TX1RX1_TURNDISABLE] = PHY_REG(RK3399_GRF_SOC_CON23, 4, 12), + [GRF_DPHY_TX1RX1_TURNREQUEST] = PHY_REG(RK3399_GRF_SOC_CON24, 4, 0), + [GRF_DPHY_RX1_SRC_SEL] = PHY_REG(RK3399_GRF_SOC_CON24, 1, 4), + [GRF_DPHY_TX1RX1_BASEDIR] = PHY_REG(RK3399_GRF_SOC_CON24, 1, 5), + [GRF_DPHY_TX1RX1_ENABLECLK] = PHY_REG(RK3399_GRF_SOC_CON24, 1, 6), + [GRF_DPHY_TX1RX1_MASTERSLAVEZ] = PHY_REG(RK3399_GRF_SOC_CON24, 1, 7), + [GRF_DPHY_RX0_TESTDIN] = PHY_REG(RK3399_GRF_SOC_CON25, 8, 0), + [GRF_DPHY_RX0_TESTEN] = PHY_REG(RK3399_GRF_SOC_CON25, 1, 8), + [GRF_DPHY_RX0_TESTCLK] = PHY_REG(RK3399_GRF_SOC_CON25, 1, 9), + [GRF_DPHY_RX0_TESTCLR] = PHY_REG(RK3399_GRF_SOC_CON25, 1, 10), + [GRF_DPHY_RX0_TESTDOUT] = PHY_REG(RK3399_GRF_SOC_STATUS1, 8, 0), +}; + struct hsfreq_range { u32 range_h; u8 cfg_bit; @@ -207,6 +250,7 @@ struct dphy_drv_data { const struct hsfreq_range *hsfreq_ranges; int num_hsfreq_ranges; const struct dphy_reg *regs; + enum mipi_dphy_ctl_type ctl_type; }; struct sensor_async_subdev { @@ -228,6 +272,7 @@ struct mipidphy_priv { struct device *dev; struct regmap *regmap_grf; const struct dphy_reg *grf_regs; + void __iomem *csihost_base_addr; struct clk *clks[MAX_DPHY_CLK]; const struct dphy_drv_data *drv_data; u64 data_rate_mbps; @@ -290,6 +335,18 @@ static void mipidphy1_wr_reg(struct mipidphy_priv *priv, unsigned char addr, writel(PHY_TESTCLK, priv->txrx_base_addr + CSIHOST_PHY_TEST_CTRL0); } +static void csi_mipidphy_wr_ths_settle(struct mipidphy_priv *priv, int hsfreq, + enum mipi_dphy_lane lane) +{ + unsigned int val; + unsigned int offset = 0x100 + 0x80 * lane; + void __iomem *csihost_base_addr = priv->csihost_base_addr; + + val = hsfreq; + val |= read_csiphy_reg(MIPI_CSI_DPHY_LANEX_THS_SETTLE_OFFSET + offset) & (~0xf); + write_csiphy_reg((MIPI_CSI_DPHY_LANEX_THS_SETTLE_OFFSET + offset), val); +} + static struct v4l2_subdev *get_remote_sensor(struct v4l2_subdev *sd) { struct media_pad *local, *remote; @@ -491,6 +548,13 @@ static const struct hsfreq_range rk3288_mipidphy_hsfreq_ranges[] = { { 999, 0x1a} }; +static const struct hsfreq_range rk3326_mipidphy_hsfreq_ranges[] = { + { 109, 0x00}, { 149, 0x01}, { 199, 0x02}, { 249, 0x03}, + { 299, 0x04}, { 399, 0x05}, { 499, 0x06}, { 599, 0x07}, + { 699, 0x08}, { 799, 0x09}, { 899, 0x0a}, {1099, 0x0b}, + {1249, 0x0c}, {1349, 0x0d}, {1500, 0x0e} +}; + static const struct hsfreq_range rk3399_mipidphy_hsfreq_ranges[] = { { 89, 0x00}, { 99, 0x10}, { 109, 0x20}, { 129, 0x01}, { 139, 0x11}, { 149, 0x21}, { 169, 0x02}, { 179, 0x12}, @@ -504,15 +568,19 @@ static const struct hsfreq_range rk3399_mipidphy_hsfreq_ranges[] = { {1399, 0x1c}, {1449, 0x2c}, {1500, 0x3c} }; -static const char * const rk3399_mipidphy_clks[] = { +static const char * const rk3288_mipidphy_clks[] = { "dphy-ref", - "dphy-cfg", - "grf", + "pclk", }; -static const char * const rk3288_mipidphy_clks[] = { +static const char * const rk3326_mipidphy_clks[] = { "dphy-ref", - "pclk", +}; + +static const char * const rk3399_mipidphy_clks[] = { + "dphy-ref", + "dphy-cfg", + "grf", }; static int mipidphy_rx_stream_on(struct mipidphy_priv *priv, @@ -621,12 +689,78 @@ static int mipidphy_txrx_stream_on(struct mipidphy_priv *priv, return 0; } +static int csi_mipidphy_stream_on(struct mipidphy_priv *priv, + struct v4l2_subdev *sd) +{ + struct v4l2_subdev *sensor_sd = get_remote_sensor(sd); + struct mipidphy_sensor *sensor = sd_to_sensor(priv, sensor_sd); + const struct dphy_drv_data *drv_data = priv->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; + void __iomem *csihost_base_addr = priv->csihost_base_addr; + + write_grf_reg(priv, GRF_DVP_V18SEL, 0x1); + + /* phy start */ + write_csiphy_reg(MIPI_CSI_DPHY_CTRL_PWRCTL_OFFSET, 0xe4); + + /* set data lane num and enable clock lane */ + write_csiphy_reg(MIPI_CSI_DPHY_CTRL_LANE_ENABLE_OFFSET, + ((GENMASK(sensor->lanes - 1, 0) << MIPI_CSI_DPHY_CTRL_DATALANE_ENABLE_OFFSET_BIT) | + (0x1 << MIPI_CSI_DPHY_CTRL_CLKLANE_ENABLE_OFFSET_BIT) | 0x1)); + + /* Reset dphy analog part */ + write_csiphy_reg(MIPI_CSI_DPHY_CTRL_PWRCTL_OFFSET, 0xe0); + usleep_range(500, 1000); + + /* Reset dphy digital part */ + write_csiphy_reg(MIPI_CSI_DPHY_CTRL_DIG_RST_OFFSET, 0x1e); + write_csiphy_reg(MIPI_CSI_DPHY_CTRL_DIG_RST_OFFSET, 0x1f); + + /* not into receive mode/wait stopstate */ + write_grf_reg(priv, GRF_DPHY_CSIPHY_FORCERXMODE, 0x0); + + /* set clock lane and data lane */ + for (i = 0; i < num_hsfreq_ranges; i++) { + if (hsfreq_ranges[i].range_h >= priv->data_rate_mbps) { + hsfreq = hsfreq_ranges[i].cfg_bit; + break; + } + } + csi_mipidphy_wr_ths_settle(priv, hsfreq, MIPI_DPHY_LANE_CLOCK); + if (sensor->lanes > 0x00) + csi_mipidphy_wr_ths_settle(priv, hsfreq, MIPI_DPHY_LANE_DATA0); + if (sensor->lanes > 0x01) + csi_mipidphy_wr_ths_settle(priv, hsfreq, MIPI_DPHY_LANE_DATA1); + if (sensor->lanes > 0x02) + csi_mipidphy_wr_ths_settle(priv, hsfreq, MIPI_DPHY_LANE_DATA2); + if (sensor->lanes > 0x03) + csi_mipidphy_wr_ths_settle(priv, hsfreq, MIPI_DPHY_LANE_DATA3); + + write_grf_reg(priv, GRF_DPHY_CSIPHY_CLKLANE_EN, 0x1); + write_grf_reg(priv, GRF_DPHY_CSIPHY_DATALANE_EN, + GENMASK(sensor->lanes - 1, 0)); + + return 0; +} + static const struct dphy_drv_data rk3288_mipidphy_drv_data = { .clks = rk3288_mipidphy_clks, .num_clks = ARRAY_SIZE(rk3288_mipidphy_clks), .hsfreq_ranges = rk3288_mipidphy_hsfreq_ranges, .num_hsfreq_ranges = ARRAY_SIZE(rk3288_mipidphy_hsfreq_ranges), .regs = rk3288_grf_dphy_regs, + .ctl_type = MIPI_DPHY_CTL_GRF_ONLY, +}; + +static const struct dphy_drv_data rk3326_mipidphy_drv_data = { + .clks = rk3326_mipidphy_clks, + .num_clks = ARRAY_SIZE(rk3326_mipidphy_clks), + .hsfreq_ranges = rk3326_mipidphy_hsfreq_ranges, + .num_hsfreq_ranges = ARRAY_SIZE(rk3326_mipidphy_hsfreq_ranges), + .regs = rk3326_grf_dphy_regs, + .ctl_type = MIPI_DPHY_CTL_CSI_HOST, }; static const struct dphy_drv_data rk3399_mipidphy_drv_data = { @@ -635,17 +769,22 @@ static const struct dphy_drv_data rk3399_mipidphy_drv_data = { .hsfreq_ranges = rk3399_mipidphy_hsfreq_ranges, .num_hsfreq_ranges = ARRAY_SIZE(rk3399_mipidphy_hsfreq_ranges), .regs = rk3399_grf_dphy_regs, + .ctl_type = MIPI_DPHY_CTL_GRF_ONLY, }; static const struct of_device_id rockchip_mipidphy_match_id[] = { { - .compatible = "rockchip,rk3399-mipi-dphy", - .data = &rk3399_mipidphy_drv_data, - }, - { .compatible = "rockchip,rk3288-mipi-dphy", .data = &rk3288_mipidphy_drv_data, }, + { + .compatible = "rockchip,rk3326-mipi-dphy", + .data = &rk3326_mipidphy_drv_data, + }, + { + .compatible = "rockchip,rk3399-mipi-dphy", + .data = &rk3399_mipidphy_drv_data, + }, {} }; MODULE_DEVICE_TABLE(of, rockchip_mipidphy_match_id); @@ -841,12 +980,18 @@ static int rockchip_mipidphy_probe(struct platform_device *pdev) priv->grf_regs = drv_data->regs; priv->drv_data = drv_data; - priv->stream_on = mipidphy_txrx_stream_on; - priv->txrx_base_addr = NULL; - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - priv->txrx_base_addr = devm_ioremap_resource(dev, res); - if (IS_ERR(priv->txrx_base_addr)) - priv->stream_on = mipidphy_rx_stream_on; + if (drv_data->ctl_type == MIPI_DPHY_CTL_CSI_HOST) { + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + priv->csihost_base_addr = devm_ioremap_resource(dev, res); + priv->stream_on = csi_mipidphy_stream_on; + } else { + priv->stream_on = mipidphy_txrx_stream_on; + priv->txrx_base_addr = NULL; + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + priv->txrx_base_addr = devm_ioremap_resource(dev, res); + if (IS_ERR(priv->txrx_base_addr)) + priv->stream_on = mipidphy_rx_stream_on; + } sd = &priv->sd; v4l2_subdev_init(sd, &mipidphy_subdev_ops); |