devicetree.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: Bjorn Andersson <bjorn.andersson@linaro.org>
To: Vinod Koul <vkoul@kernel.org>
Cc: Kishon Vijay Abraham I <kishon@ti.com>,
	Rob Herring <robh+dt@kernel.org>,
	Greg Kroah-Hartman <gregkh@linuxfoundation.org>,
	Heikki Krogerus <heikki.krogerus@linux.intel.com>,
	Hans de Goede <hdegoede@redhat.com>,
	"Rafael J. Wysocki" <rafael@kernel.org>,
	linux-arm-msm@vger.kernel.org, linux-phy@lists.infradead.org,
	devicetree@vger.kernel.org, linux-kernel@vger.kernel.org,
	linux-usb@vger.kernel.org
Subject: Re: [PATCH 2/8] phy: qcom-qmp: Register typec mux and orientation switch
Date: Fri, 7 Jan 2022 11:15:49 -0800	[thread overview]
Message-ID: <YdiRZUV0oJfsdHZV@ripper> (raw)
In-Reply-To: <Ycvx2qOlPsVIjkHq@matsya>

On Tue 28 Dec 21:27 PST 2021, Vinod Koul wrote:

> On 27-12-21, 21:21, Bjorn Andersson wrote:
> > The QMP PHY handles muxing of USB vs DisplayPort, as well as orientation
> > switching of the SuperSpeed lanes. So register typec handlers for the
> > two types.
> > 
> > The TypeC mux allows switching between four lanes of DisplayPort and a
> > mixed USB+DP combination. This makes it possible to reach resolutions
> > that requires 4 lanes.
> > 
> > The TypeC switch allows switching the SuperSpeed pins and have been
> > tested with both 2 and 4 lane DisplayPort.
> > 
> > It's possible that in the USB mode the DP_MODE should be disabled, but
> > this is left untouched.
> > 
> > Signed-off-by: Bjorn Andersson <bjorn.andersson@linaro.org>
> > ---
> > 
> > My suggestion is that if/once this patch is deemed acceptable the PHY
> > maintainers could create a immutable branch/tag which can be merged into the
> > PHY tree as well as the USB tree.
> > 
> >  drivers/phy/qualcomm/phy-qcom-qmp.c | 176 +++++++++++++++++++++++++---
> >  1 file changed, 158 insertions(+), 18 deletions(-)
> > 
> > diff --git a/drivers/phy/qualcomm/phy-qcom-qmp.c b/drivers/phy/qualcomm/phy-qcom-qmp.c
> > index 7bea6a60dc54..8d8139df9d8e 100644
> > --- a/drivers/phy/qualcomm/phy-qcom-qmp.c
> > +++ b/drivers/phy/qualcomm/phy-qcom-qmp.c
> > @@ -19,6 +19,8 @@
> >  #include <linux/regulator/consumer.h>
> >  #include <linux/reset.h>
> >  #include <linux/slab.h>
> > +#include <linux/usb/typec_dp.h>
> > +#include <linux/usb/typec_mux.h>
> >  
> >  #include <dt-bindings/phy/phy.h>
> >  
> > @@ -3017,6 +3019,9 @@ struct qmp_phy_dp_clks {
> >   * @phy_mutex: mutex lock for PHY common block initialization
> >   * @init_count: phy common block initialization count
> >   * @ufs_reset: optional UFS PHY reset handle
> > + * @sw: typec switch for receiving orientation changes
> > + * @mux: typec mux for DP muxing
> > + * @orientation: carries current CC orientation
> >   */
> >  struct qcom_qmp {
> >  	struct device *dev;
> > @@ -3032,6 +3037,10 @@ struct qcom_qmp {
> >  	int init_count;
> >  
> >  	struct reset_control *ufs_reset;
> > +
> > +	struct typec_switch *sw;
> > +	struct typec_mux *mux;
> > +	enum typec_orientation orientation;
> >  };
> >  
> >  static void qcom_qmp_v3_phy_dp_aux_init(struct qmp_phy *qphy);
> > @@ -4378,30 +4387,23 @@ static void qcom_qmp_v3_phy_configure_dp_tx(struct qmp_phy *qphy)
> >  
> >  static bool qcom_qmp_phy_configure_dp_mode(struct qmp_phy *qphy)
> >  {
> > +	const struct phy_configure_opts_dp *dp_opts = &qphy->dp_opts;
> > +	bool reverse = qphy->qmp->orientation == TYPEC_ORIENTATION_REVERSE;
> >  	u32 val;
> > -	bool reverse = false;
> >  
> >  	val = DP_PHY_PD_CTL_PWRDN | DP_PHY_PD_CTL_AUX_PWRDN |
> >  	      DP_PHY_PD_CTL_PLL_PWRDN | DP_PHY_PD_CTL_DP_CLAMP_EN;
> >  
> > -	/*
> > -	 * TODO: Assume orientation is CC1 for now and two lanes, need to
> > -	 * use type-c connector to understand orientation and lanes.
> > -	 *
> > -	 * Otherwise val changes to be like below if this code understood
> > -	 * the orientation of the type-c cable.
> > -	 *
> > -	 * if (lane_cnt == 4 || orientation == ORIENTATION_CC2)
> > -	 *	val |= DP_PHY_PD_CTL_LANE_0_1_PWRDN;
> > -	 * if (lane_cnt == 4 || orientation == ORIENTATION_CC1)
> > -	 *	val |= DP_PHY_PD_CTL_LANE_2_3_PWRDN;
> > -	 * if (orientation == ORIENTATION_CC2)
> > -	 *	writel(0x4c, qphy->pcs + QSERDES_V3_DP_PHY_MODE);
> > -	 */
> > -	val |= DP_PHY_PD_CTL_LANE_2_3_PWRDN;
> > +	if (dp_opts->lanes == 4 || reverse)
> > +		val |= DP_PHY_PD_CTL_LANE_0_1_PWRDN;
> > +	if (dp_opts->lanes == 4 || !reverse)
> > +		val |= DP_PHY_PD_CTL_LANE_2_3_PWRDN;
> >  	writel(val, qphy->pcs + QSERDES_DP_PHY_PD_CTL);
> >  
> > -	writel(0x5c, qphy->pcs + QSERDES_DP_PHY_MODE);
> > +	if (reverse)
> > +		writel(0x4c, qphy->pcs + QSERDES_DP_PHY_MODE);
> > +	else
> > +		writel(0x5c, qphy->pcs + QSERDES_DP_PHY_MODE);
> >  
> >  	return reverse;
> >  }
> > @@ -5809,6 +5811,123 @@ static const struct dev_pm_ops qcom_qmp_phy_pm_ops = {
> >  			   qcom_qmp_phy_runtime_resume, NULL)
> >  };
> >  
> > +#if IS_ENABLED(CONFIG_TYPEC)
> > +static int qcom_qmp_phy_typec_switch_set(struct typec_switch *sw,
> > +		enum typec_orientation orientation)
> 
> pls align to preceding open brace (here and other places)
> 

Sure thing.

> > +{
> > +	struct qcom_qmp *qmp = typec_switch_get_drvdata(sw);
> > +	void __iomem *dp_com = qmp->dp_com;
> > +
> > +	qmp->orientation = orientation;
> > +
> > +	if (orientation == TYPEC_ORIENTATION_REVERSE)
> > +		qphy_setbits(dp_com, QPHY_V3_DP_COM_TYPEC_CTRL, 0x01);
> > +	else
> > +		qphy_clrbits(dp_com, QPHY_V3_DP_COM_TYPEC_CTRL, 0x01);
> > +
> > +	return 0;
> > +}
> > +
> > +static int qcom_qmp_phy_typec_mux_set(struct typec_mux *mux,
> > +				      struct typec_mux_state *state)
> > +{
> > +	struct qcom_qmp *qmp = typec_mux_get_drvdata(mux);
> > +	void __iomem *dp_com = qmp->dp_com;
> > +	bool dp_mode;
> > +	bool usb_mode;
> > +
> > +	switch (state->mode) {
> > +	case TYPEC_STATE_SAFE:
> > +	case TYPEC_STATE_USB:
> > +		/*
> > +		 * TODO: Figure out if we should clear DP_MODE when we enter a
> > +		 * USB-only state.
> > +		 */
> > +		dp_mode = true;
> 
> should this be false for these states?
> 

I think it should, but figured that I better change the behavior in a
separate follow-up commit. Might also be that SAFE should be
false/false - or in some other way turning off the output.

Hence the TODO.

> > +		usb_mode = true;
> > +		break;
> > +	case TYPEC_DP_STATE_A:
> > +	case TYPEC_DP_STATE_C:
> > +	case TYPEC_DP_STATE_E:
> > +		dp_mode = true;
> > +		usb_mode = false;
> > +		break;
> > +	case TYPEC_DP_STATE_B:
> > +	case TYPEC_DP_STATE_D:
> > +	case TYPEC_DP_STATE_F:
> > +		dp_mode = true;
> > +		usb_mode = true;
> > +		break;
> > +	}
> 
> looks like dp_mode is true always. And only for DP state A C E, usb_mode
> is false...
> 

A, C and E are 4-lanes DP, while B, D, F are 2-lane DP and 2-lane USB.

> > +
> > +	qphy_setbits(dp_com, QPHY_V3_DP_COM_RESET_OVRD_CTRL,
> > +		     SW_DPPHY_RESET_MUX | SW_USB3PHY_RESET_MUX);
> > +	if (dp_mode)
> > +		qphy_setbits(dp_com, QPHY_V3_DP_COM_PHY_MODE_CTRL, DP_MODE);
> > +	else
> > +		qphy_clrbits(dp_com, QPHY_V3_DP_COM_PHY_MODE_CTRL, DP_MODE);
> > +
> > +	if (usb_mode)
> > +		qphy_setbits(dp_com, QPHY_V3_DP_COM_PHY_MODE_CTRL, USB3_MODE);
> > +	else
> > +		qphy_clrbits(dp_com, QPHY_V3_DP_COM_PHY_MODE_CTRL, USB3_MODE);
> > +
> > +	qphy_setbits(dp_com, QPHY_V3_DP_COM_SW_RESET, SW_RESET);
> > +	qphy_clrbits(dp_com, QPHY_V3_DP_COM_SWI_CTRL, 0x03);
> > +	qphy_clrbits(dp_com, QPHY_V3_DP_COM_SW_RESET, SW_RESET);
> > +
> > +	return 0;
> > +}
> > +
> > +static int qcom_qmp_phy_typec_register(struct qcom_qmp *qmp,
> > +				       const struct qmp_phy_cfg *cfg)
> > +{
> > +	struct typec_switch_desc sw_desc = {};
> > +	struct typec_mux_desc mux_desc = {};
> > +	struct device *dev = qmp->dev;
> > +
> > +	if (!cfg->has_phy_dp_com_ctrl)
> > +		return 0;
> > +
> > +	sw_desc.drvdata = qmp;
> > +	sw_desc.fwnode = dev->fwnode;
> > +	sw_desc.set = qcom_qmp_phy_typec_switch_set;
> > +	qmp->sw = typec_switch_register(dev, &sw_desc);
> > +	if (IS_ERR(qmp->sw)) {
> > +		dev_err(dev, "Error registering typec switch: %pe\n", qmp->sw);
> > +		return PTR_ERR(qmp->sw);
> > +	}
> > +
> > +	mux_desc.drvdata = qmp;
> > +	mux_desc.fwnode = dev->fwnode;
> > +	mux_desc.set = qcom_qmp_phy_typec_mux_set;
> > +	qmp->mux = typec_mux_register(dev, &mux_desc);
> > +	if (IS_ERR(qmp->mux)) {
> > +		dev_err(dev, "Error registering typec mux: %pe\n", qmp->mux);
> > +		typec_switch_unregister(qmp->sw);
> > +		return PTR_ERR(qmp->mux);
> > +	}
> > +
> > +	return 0;
> > +}
> > +
> > +static void qcom_qmp_phy_typec_unregister(struct qcom_qmp *qmp)
> > +{
> > +	typec_mux_unregister(qmp->mux);
> > +	typec_switch_unregister(qmp->sw);
> > +}
> > +#else
> 
> empty line here pls
> 

Okay.

Thanks,
Bjorn

> > +static int qcom_qmp_phy_typec_register(struct qcom_qmp *qmp,
> > +				       const struct qmp_phy_cfg *cfg)
> > +{
> > +	return 0;
> > +}
> > +
> > +static void qcom_qmp_phy_typec_unregister(struct qcom_qmp *qmp)
> > +{
> > +}
> > +#endif
> > +
> >  static int qcom_qmp_phy_probe(struct platform_device *pdev)
> >  {
> >  	struct qcom_qmp *qmp;
> > @@ -5891,7 +6010,15 @@ static int qcom_qmp_phy_probe(struct platform_device *pdev)
> >  		return ret;
> >  	}
> >  
> > -	num = of_get_available_child_count(dev->of_node);
> > +	ret = qcom_qmp_phy_typec_register(qmp, cfg);
> > +	if (ret)
> > +		return ret;
> > +
> > +	num = 0;
> > +	for_each_available_child_of_node(dev->of_node, child) {
> > +		if (!of_node_name_eq(child, "port"))
> > +			num++;
> > +	}
> >  	/* do we have a rogue child node ? */
> >  	if (num > expected_phys)
> >  		return -EINVAL;
> > @@ -5918,6 +6045,9 @@ static int qcom_qmp_phy_probe(struct platform_device *pdev)
> >  			serdes = usb_serdes;
> >  		}
> >  
> > +		if (of_node_name_eq(child, "port"))
> > +			continue;
> > +
> >  		/* Create per-lane phy */
> >  		ret = qcom_qmp_phy_create(dev, child, id, serdes, cfg);
> >  		if (ret) {
> > @@ -5962,8 +6092,18 @@ static int qcom_qmp_phy_probe(struct platform_device *pdev)
> >  	return ret;
> >  }
> >  
> > +static int qcom_qmp_phy_remove(struct platform_device *pdev)
> > +{
> > +	struct qcom_qmp *qmp = platform_get_drvdata(pdev);
> > +
> > +	qcom_qmp_phy_typec_unregister(qmp);
> > +
> > +	return 0;
> > +}
> > +
> >  static struct platform_driver qcom_qmp_phy_driver = {
> >  	.probe		= qcom_qmp_phy_probe,
> > +	.remove		= qcom_qmp_phy_remove,
> >  	.driver = {
> >  		.name	= "qcom-qmp-phy",
> >  		.pm	= &qcom_qmp_phy_pm_ops,
> > -- 
> > 2.33.1
> 
> -- 
> ~Vinod

  reply	other threads:[~2022-01-07 19:15 UTC|newest]

Thread overview: 29+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2021-12-28  5:21 [PATCH 0/8] typec: mux: Introduce support for multiple TypeC muxes Bjorn Andersson
2021-12-28  5:21 ` [PATCH 1/8] dt-bindings: phy: qcom,qmp-usb3-dp: Add altmode/switch properties Bjorn Andersson
2021-12-28  5:21 ` [PATCH 2/8] phy: qcom-qmp: Register typec mux and orientation switch Bjorn Andersson
2021-12-28 12:25   ` Dmitry Baryshkov
2021-12-28 13:59   ` kernel test robot
2021-12-28 16:20     ` Bjorn Andersson
2021-12-29  5:27   ` Vinod Koul
2022-01-07 19:15     ` Bjorn Andersson [this message]
2021-12-28  5:21 ` [PATCH 3/8] device property: Helper to match multiple connections Bjorn Andersson
2021-12-28 13:09   ` Dmitry Baryshkov
2021-12-28 17:04     ` Bjorn Andersson
2021-12-28 18:24       ` Dmitry Baryshkov
2021-12-28 18:42         ` Bjorn Andersson
2021-12-29  5:40       ` Vinod Koul
2021-12-30  9:26   ` Heikki Krogerus
2021-12-31  9:09     ` Sakari Ailus
2022-01-05 20:43       ` Bjorn Andersson
2022-01-07 14:33         ` Sakari Ailus
2022-01-07 15:15           ` Bjorn Andersson
2021-12-28  5:21 ` [PATCH 4/8] device property: Use multi-connection matchers for single case Bjorn Andersson
2021-12-28  5:21 ` [PATCH 5/8] typec: mux: Introduce indirection Bjorn Andersson
2021-12-28  5:21 ` [PATCH 6/8] typec: mux: Allow multiple mux_devs per mux Bjorn Andersson
2021-12-28 16:04   ` Dmitry Baryshkov
2021-12-28 16:40     ` Bjorn Andersson
2022-01-06 10:43   ` Dan Carpenter
2021-12-28  5:21 ` [PATCH 7/8] dt-bindings: usb: Add binding for fcs,fsa4480 Bjorn Andersson
2021-12-28  5:21 ` [PATCH 8/8] usb: typec: mux: Add On Semi fsa4480 driver Bjorn Andersson
2021-12-28 12:20 ` [PATCH 0/8] typec: mux: Introduce support for multiple TypeC muxes Hans de Goede
2021-12-28 17:08   ` Bjorn Andersson

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=YdiRZUV0oJfsdHZV@ripper \
    --to=bjorn.andersson@linaro.org \
    --cc=devicetree@vger.kernel.org \
    --cc=gregkh@linuxfoundation.org \
    --cc=hdegoede@redhat.com \
    --cc=heikki.krogerus@linux.intel.com \
    --cc=kishon@ti.com \
    --cc=linux-arm-msm@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-phy@lists.infradead.org \
    --cc=linux-usb@vger.kernel.org \
    --cc=rafael@kernel.org \
    --cc=robh+dt@kernel.org \
    --cc=vkoul@kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).