Browse Source

phy: ti: j721e-wiz: Implement DisplayPort mode to the wiz driver

For DisplayPort use we need to set WIZ_CONFIG_LANECTL register's
P_STANDARD_MODE bits to "mode 3". In the DisplayPort use also the
P_ENABLE bits of the same register are set to P_ENABLE instead of
P_ENABLE_FORCE, so that the DisplayPort driver can enable and disable
the lane as needed. The DisplayPort mode is selected according to
lane<n>-mode -property. All other values of lane<n>-mode -property but
PHY_TYPE_DP will set P_STANDARD_MODE bits to 0 and P_ENABLE bits to
force enable.

History

This patch replaces the earlier hard coded hack for DisplayPort use
and uses new "port-use" dts property to select use mode for each lane
separately.

It appears the only mandatory part of the earlier hack was setting a
different mode for all the DP lanes. Also the LANECTL P0_FORCE_ENABLE
for lane 0 is changed to P0_ENABLE. The both settings appear to work,
but using P0_FORCE_ENABLE may prevent lane reset from the controller
to take effect.

With this patch the DisplayPort still works, but all the register do
not have the same values as before.

Here is the diff between wiz setting before and after this patch:

Register                   | Earlier    | Now        | Functional change
WIZ_SERDES_TOP_CTRL 0x408  | 0x30000000 | 0xb8000000 | Ext ref clk only [1]
WIZ_SERDES_RST      0x40c  | 0x39000000 | 0x31000000 | Ext ref clk only [2]
WIZ_LANECTL(0)      0x480  | 0x70000000 | 0x80000000 | Force enable, align.. [3]
WIZ_LANECTL(1)      0x4c0  | 0x80000000 | 0x80000000 |
WIZ_LANECTL(2)      0x500  | 0x80000000 | 0x80000000 |
WIZ_LANECTL(3)      0x540  | 0x80000000 | 0x80000000 |
WIZ_LANEDIV(0)      0x484  | 0x00010001 | 0x00000000 | The divider is unused
WIZ_LANEDIV(1)      0x4c4  | 0x00010001 | 0x00000000 | The divider is unused
WIZ_LANEDIV(2)      0x504  | 0x00010001 | 0x00000000 | The divider is unused
WIZ_LANEDIV(3)      0x544  | 0x00010001 | 0x00000000 | The divider is unused

The above is before Wiz is taken out of reset (0x40c bit 31).

[1] Bits 31-30 sets external PMA common differential reference clock
    mode. Setting 10 is for under 100Mhz rates (the old 00 is for greater
    than 100MHz rates). J721E evm uses internal reference clock.

[2] Bit 27 disables termination for the external PMA common differential
    reference clock. J721E evm uses internal reference clock.

[3] Bit 29 is auto align to 8B10B comma characters and 28 is auto
    sequence the RAW interface according to the configuration
    settings, neither should affect DisplayPort behavior. Bit 31 is
    normal enable and 30 is force enable.

Signed-off-by: Jyri Sarha <jsarha@ti.com>
Jyri Sarha 6 years ago
parent
commit
a4456f2bad
1 changed files with 51 additions and 4 deletions
  1. 51 4
      drivers/phy/ti/phy-j721e-wiz.c

+ 51 - 4
drivers/phy/ti/phy-j721e-wiz.c

@@ -20,6 +20,7 @@
 #include <linux/pm_runtime.h>
 #include <linux/regmap.h>
 #include <linux/reset-controller.h>
+#include <dt-bindings/phy/phy.h>
 
 #define WIZ_SERDES_CTRL		0x404
 #define WIZ_SERDES_TOP_CTRL	0x408
@@ -78,6 +79,8 @@ static const struct reg_field p_enable[WIZ_MAX_LANES] = {
 	REG_FIELD(WIZ_LANECTL(3), 30, 31),
 };
 
+enum p_enable { P_ENABLE = 2, P_ENABLE_FORCE = 1, P_ENABLE_DISABLE = 0 };
+
 static const struct reg_field p_align[WIZ_MAX_LANES] = {
 	REG_FIELD(WIZ_LANECTL(0), 29, 29),
 	REG_FIELD(WIZ_LANECTL(1), 29, 29),
@@ -214,6 +217,7 @@ struct wiz {
 	int			typec_dir_delay;
 
 	enum wiz_type type;
+	u32 lane_modes[WIZ_MAX_LANES];
 };
 
 static int wiz_reset(struct wiz *wiz)
@@ -236,12 +240,17 @@ static int wiz_reset(struct wiz *wiz)
 static int wiz_mode_select(struct wiz *wiz)
 {
 	u32 num_lanes = wiz->num_lanes;
+	enum wiz_lane_standard_mode mode;
 	int ret;
 	int i;
 
 	for (i = 0; i < num_lanes; i++) {
-		ret = regmap_field_write(wiz->p_standard_mode[i],
-					 LANE_MODE_GEN4);
+		if (wiz->lane_modes[i] == PHY_TYPE_DP)
+			mode = LANE_MODE_GEN1;
+		else
+			mode = LANE_MODE_GEN4;
+
+		ret = regmap_field_write(wiz->p_standard_mode[i], mode);
 		if (ret)
 			return ret;
 	}
@@ -699,7 +708,7 @@ static int wiz_phy_reset_assert(struct reset_controller_dev *rcdev,
 		return ret;
 	}
 
-	ret = regmap_field_write(wiz->p_enable[id - 1], false);
+	ret = regmap_field_write(wiz->p_enable[id - 1], P_ENABLE_DISABLE);
 	return ret;
 }
 
@@ -730,7 +739,11 @@ static int wiz_phy_reset_deassert(struct reset_controller_dev *rcdev,
 		return ret;
 	}
 
-	ret = regmap_field_write(wiz->p_enable[id - 1], true);
+	if (wiz->lane_modes[id - 1] == PHY_TYPE_DP)
+		ret = regmap_field_write(wiz->p_enable[id - 1], P_ENABLE);
+	else
+		ret = regmap_field_write(wiz->p_enable[id - 1], P_ENABLE_FORCE);
+
 	return ret;
 }
 
@@ -757,6 +770,33 @@ static const struct of_device_id wiz_id_table[] = {
 };
 MODULE_DEVICE_TABLE(of, wiz_id_table);
 
+static int wiz_get_lane_mode(struct device *dev, int lane_number,
+			     u32 *lane_mode)
+{
+	char property_name[11]; /* 11 is length of "lane0-mode\0" */
+	int ret;
+
+	ret = snprintf(property_name, sizeof(property_name), "lane%u-mode",
+		       lane_number);
+
+	if (ret != 10) { /* 10 is length of "lane0-mode" */
+		dev_err(dev, "%s: bad lane number %d (ret = %d)\n",
+			__func__, lane_number, ret);
+		return -ENOTSUPP;
+	}
+
+	ret = of_property_read_u32(dev->of_node, property_name, lane_mode);
+	if (ret == -EINVAL) {
+		*lane_mode = PHY_NONE;
+		return 0;
+	} else if (ret) {
+		dev_err(dev, "Getting \"%s\" property failed: %d\n",
+			property_name, ret);
+	}
+
+	return ret;
+}
+
 static int wiz_probe(struct platform_device *pdev)
 {
 	struct reset_controller_dev *phy_reset_dev;
@@ -770,6 +810,7 @@ static int wiz_probe(struct platform_device *pdev)
 	struct wiz *wiz;
 	u32 num_lanes;
 	int ret;
+	int i;
 
 	wiz = devm_kzalloc(dev, sizeof(*wiz), GFP_KERNEL);
 	if (!wiz)
@@ -829,6 +870,12 @@ static int wiz_probe(struct platform_device *pdev)
 		}
 	}
 
+	for (i = 0; i < num_lanes; i++) {
+		ret = wiz_get_lane_mode(dev, i, &wiz->lane_modes[i]);
+		if (ret)
+			return ret;
+	}
+
 	wiz->dev = dev;
 	wiz->regmap = regmap;
 	wiz->num_lanes = num_lanes;