@@ -217,6 +217,17 @@ static void phy_update_bits(struct inno_dsidphy *inno,
writel(tmp, inno->phy_base + reg);
}
+static void host_update_bits(struct inno_dsidphy *inno,
+ u32 reg, u32 mask, u32 val)
+{
+ unsigned int tmp, orig;
+
+ orig = readl(inno->host_base + reg);
+ tmp = orig & ~mask;
+ tmp |= val & mask;
+ writel(tmp, inno->host_base + reg);
+}
+
static int inno_is_valid_phy_mode(struct inno_dsidphy *inno)
{
switch (inno->mode) {
@@ -224,6 +235,10 @@ static int inno_is_valid_phy_mode(struct inno_dsidphy *inno)
break;
case PHY_MODE_LVDS:
break;
+ case PHY_MODE_TTL:
+ if (IS_ERR(inno->host_base))
+ return -EINVAL;
+ break;
default:
return -EINVAL;
}
@@ -506,6 +521,32 @@ static void inno_dsidphy_lvds_mode_enable(struct inno_dsidphy *inno)
LVDS_DATA_LANE2_EN | LVDS_DATA_LANE3_EN);
}
+static void inno_dsidphy_ttl_mode_enable(struct inno_dsidphy *inno)
+{
+ /* Select TTL mode */
+ phy_update_bits(inno, REGISTER_PART_LVDS, 0x03,
+ MODE_ENABLE_MASK, TTL_MODE_ENABLE);
+ /* Reset digital logic */
+ phy_update_bits(inno, REGISTER_PART_LVDS, 0x00,
+ LVDS_DIGITAL_INTERNAL_RESET_MASK,
+ LVDS_DIGITAL_INTERNAL_RESET_ENABLE);
+ udelay(1);
+ phy_update_bits(inno, REGISTER_PART_LVDS, 0x00,
+ LVDS_DIGITAL_INTERNAL_RESET_MASK,
+ LVDS_DIGITAL_INTERNAL_RESET_DISABLE);
+ /* Enable digital logic */
+ phy_update_bits(inno, REGISTER_PART_LVDS, 0x01,
+ LVDS_DIGITAL_INTERNAL_ENABLE_MASK,
+ LVDS_DIGITAL_INTERNAL_ENABLE);
+ /* Enable analog driver */
+ phy_update_bits(inno, REGISTER_PART_LVDS, 0x0b,
+ LVDS_LANE_EN_MASK, LVDS_CLK_LANE_EN |
+ LVDS_DATA_LANE0_EN | LVDS_DATA_LANE1_EN |
+ LVDS_DATA_LANE2_EN | LVDS_DATA_LANE3_EN);
+ /* Enable for clk lane in TTL mode */
+ host_update_bits(inno, DSI_PHY_RSTZ, PHY_ENABLECLK, PHY_ENABLECLK);
+}
+
static int inno_dsidphy_power_on(struct phy *phy)
{
struct inno_dsidphy *inno = phy_get_drvdata(phy);
@@ -533,6 +574,9 @@ static int inno_dsidphy_power_on(struct phy *phy)
case PHY_MODE_LVDS:
inno_dsidphy_lvds_mode_enable(inno);
break;
+ case PHY_MODE_TTL:
+ inno_dsidphy_ttl_mode_enable(inno);
+ break;
default:
return -EINVAL;
}
@@ -561,6 +605,10 @@ static int inno_dsidphy_power_off(struct phy *phy)
LVDS_PLL_POWER_MASK | LVDS_BANDGAP_POWER_MASK,
LVDS_PLL_POWER_OFF | LVDS_BANDGAP_POWER_DOWN);
+ /* Disable for clk lane in TTL mode */
+ if (!IS_ERR(inno->host_base))
+ host_update_bits(inno, DSI_PHY_RSTZ, PHY_ENABLECLK, 0);
+
pm_runtime_put(inno->dev);
clk_disable_unprepare(inno->ref_clk);
clk_disable_unprepare(inno->pclk_phy);
@@ -576,6 +624,7 @@ static int inno_dsidphy_set_mode(struct phy *phy, enum phy_mode mode,
switch (mode) {
case PHY_MODE_MIPI_DPHY:
case PHY_MODE_LVDS:
+ case PHY_MODE_TTL:
inno->mode = mode;
break;
default:
@@ -630,6 +679,10 @@ static int inno_dsidphy_probe(struct platform_device *pdev)
if (IS_ERR(inno->phy_base))
return PTR_ERR(inno->phy_base);
+ inno->host_base = devm_platform_ioremap_resource(pdev, 1);
+ if (IS_ERR(inno->host_base))
+ dev_warn(dev, "TTL mode is not supported\n");
+
inno->ref_clk = devm_clk_get(dev, "ref");
if (IS_ERR(inno->ref_clk)) {
ret = PTR_ERR(inno->ref_clk);
The rockchip phy can be programmed in 3 modes: - dsi - lvds - ttl For instance in px30 there are two sets of rgb interface pins m0 and m1. The logic can go outside from the VOP using m0 set or go outside using the m1 set and the ttl logic enable. There are combination where a set of pin can be taken from m1 and m0 where all the two path are enabled. dsi and ttl enable share one register in their register area. Simple implementation is overlap the area where we want access the register Signed-off-by: Michael Trimarchi <michael@amarulasolutions.com> --- .../phy/rockchip/phy-rockchip-inno-dsidphy.c | 53 +++++++++++++++++++ 1 file changed, 53 insertions(+)