From: Krzysztof Kozlowski <krzk@kernel.org>
To: Peter Geis <pgwipeout@gmail.com>, Heiko Stuebner <heiko@sntech.de>
Cc: zyw@rock-chips.com, kever.yang@rock-chips.com,
frank.wang@rock-chips.com, william.wu@rock-chips.com,
wulf@rock-chips.com, linux-rockchip@lists.infradead.org,
Algea Cao <algea.cao@rock-chips.com>,
Arnd Bergmann <arnd@arndb.de>,
Cristian Ciocaltea <cristian.ciocaltea@collabora.com>,
Kishon Vijay Abraham I <kishon@kernel.org>,
Philipp Zabel <p.zabel@pengutronix.de>,
Sebastian Reichel <sebastian.reichel@collabora.com>,
Vinod Koul <vkoul@kernel.org>,
Zhang Yubing <yubing.zhang@rock-chips.com>,
linux-arm-kernel@lists.infradead.org,
linux-kernel@vger.kernel.org, linux-phy@lists.infradead.org
Subject: Re: [RFC PATCH v1 3/6] phy: rockchip: add driver for rk3328 usb3 phy
Date: Thu, 16 Jan 2025 13:59:38 +0100 [thread overview]
Message-ID: <87001334-5a37-4fba-b08c-3679fb556f83@kernel.org> (raw)
In-Reply-To: <20250115012628.1035928-4-pgwipeout@gmail.com>
On 15/01/2025 02:26, Peter Geis wrote:
> The rk3328 has a combined usb2 and usb3 phy block for the usb3 dwc
> interface. The implementation up until now has been bugged, with
> multiple issues ranging from disconnect detection failures to low
> performance. This driver fixes the majority of the original issues and
> allows better performance for the rk3328 usb3 port.
>
> This driver sources data from multiple sources, including the rk3328
> trm, the rk3228h trm, emails from Rockchip, and both the 4.4 and 5.10
> downstream drivers. The current implementation allows for basic bring up
> of the phy block and fixes the detection issues. Interrupts are enabled,
> but currently only used for debugging. Features missing currently are
> power management, OTG handling, board specific tuning, regulator control,
>
> Currently the only known bugs are a AX88179 usb3 gigabit adapter crashes
> when operating at usb3 speeds and transmitting large amounts of data and
> full disconnection detections may be slower than expected (~5-10 seconds).
>
> Signed-off-by: Peter Geis <pgwipeout@gmail.com>
> ---
...
> +}
> +
> +static int rockchip_usb3phy_parse_dt(struct rockchip_usb3phy *usb3phy, struct device *dev)
> +{
> + int ret;
> +
> + usb3phy->clk_pipe = devm_clk_get(dev, "usb3phy-pipe");
> + if (IS_ERR(usb3phy->clk_pipe)) {
> + dev_err(dev, "could not get usb3phy pipe clock\n");
Syntax is always:
return dev_err_probe
> + return PTR_ERR(usb3phy->clk_pipe);
> + }
> +
> + usb3phy->clk_otg = devm_clk_get(dev, "usb3phy-otg");
> + if (IS_ERR(usb3phy->clk_otg)) {
> + dev_err(dev, "could not get usb3phy otg clock\n");
> + return PTR_ERR(usb3phy->clk_otg);
> + }
> +
> + usb3phy->clk_ref = devm_clk_get(dev, "refclk-usb3otg");
> + if (IS_ERR(usb3phy->clk_ref)) {
> + dev_err(dev, "could not get usb3phy ref clock\n");
> + return PTR_ERR(usb3phy->clk_ref);
> + }
> +
> + usb3phy->u2por_rst = devm_reset_control_get(dev, "usb3phy-u2-por");
> + if (IS_ERR(usb3phy->u2por_rst)) {
> + dev_err(dev, "no usb3phy-u2-por reset control found\n");
> + return PTR_ERR(usb3phy->u2por_rst);
> + }
> +
> + usb3phy->u3por_rst = devm_reset_control_get(dev, "usb3phy-u3-por");
> + if (IS_ERR(usb3phy->u3por_rst)) {
> + dev_err(dev, "no usb3phy-u3-por reset control found\n");
> + return PTR_ERR(usb3phy->u3por_rst);
> + }
> +
> + usb3phy->pipe_rst = devm_reset_control_get(dev, "usb3phy-pipe-mac");
> + if (IS_ERR(usb3phy->pipe_rst)) {
> + dev_err(dev, "no usb3phy_pipe_mac reset control found\n");
> + return PTR_ERR(usb3phy->pipe_rst);
> + }
> +
> + usb3phy->utmi_rst = devm_reset_control_get(dev, "usb3phy-utmi-mac");
> + if (IS_ERR(usb3phy->utmi_rst)) {
> + dev_err(dev, "no usb3phy-utmi-mac reset control found\n");
> + return PTR_ERR(usb3phy->utmi_rst);
> + }
> +
> + usb3phy->pipe_apb_rst = devm_reset_control_get(dev, "usb3phy-pipe-apb");
> + if (IS_ERR(usb3phy->pipe_apb_rst)) {
> + dev_err(dev, "no usb3phy-pipe-apb reset control found\n");
> + return PTR_ERR(usb3phy->pipe_apb_rst);
> + }
> +
> + usb3phy->utmi_apb_rst = devm_reset_control_get(dev, "usb3phy-utmi-apb");
> + if (IS_ERR(usb3phy->utmi_apb_rst)) {
> + dev_err(dev, "no usb3phy-utmi-apb reset control found\n");
> + return PTR_ERR(usb3phy->utmi_apb_rst);
> + }
> +
> + usb3phy->ls_irq = of_irq_get_byname(dev->of_node, "linestate");
> + if (usb3phy->ls_irq < 0) {
> + dev_err(dev, "no linestate irq provided\n");
> + return usb3phy->ls_irq;
> + }
> +
> + ret = devm_request_threaded_irq(dev, usb3phy->ls_irq, NULL, rockchip_usb3phy_linestate_irq,
> + IRQF_ONESHOT, "rockchip_usb3phy_ls", usb3phy);
> + if (ret) {
> + dev_err(dev, "failed to request linestate irq handle\n");
> + return ret;
> + }
> +
> + usb3phy->bvalid_irq = of_irq_get_byname(dev->of_node, "bvalid");
> + if (usb3phy->bvalid_irq < 0) {
> + dev_err(dev, "no bvalid irq provided\n");
> + return usb3phy->bvalid_irq;
> + }
> +
> + ret = devm_request_threaded_irq(dev, usb3phy->bvalid_irq, NULL, rockchip_usb3phy_bvalid_irq,
> + IRQF_ONESHOT, "rockchip_usb3phy_bvalid", usb3phy);
> + if (ret) {
> + dev_err(dev, "failed to request bvalid irq handle\n");
> + return ret;
> + }
> +
> + usb3phy->id_irq = of_irq_get_byname(dev->of_node, "id");
> + if (usb3phy->id_irq < 0) {
> + dev_err(dev, "no id irq provided\n");
> + return usb3phy->id_irq;
> + }
> +
> + ret = devm_request_threaded_irq(dev, usb3phy->id_irq, NULL, rockchip_usb3phy_id_irq,
> + IRQF_ONESHOT, "rockchip_usb3phy-id", usb3phy);
> + if (ret) {
> + dev_err(dev, "failed to request id irq handle\n");
> + return ret;
> + }
> +
> + usb3phy->rxdet_irq = of_irq_get_byname(dev->of_node, "rxdet");
> + if (usb3phy->rxdet_irq < 0) {
> + dev_err(dev, "no rxdet irq provided\n");
> + return usb3phy->rxdet_irq;
> + }
> +
> + ret = devm_request_threaded_irq(dev, usb3phy->rxdet_irq, NULL, rockchip_usb3phy_rxdet_irq,
> + IRQF_ONESHOT, "rockchip_usb3phy-rxdet", usb3phy);
> + if (ret) {
> + dev_err(dev, "failed to request rxdet irq handle\n");
> + return ret;
> + }
> +
> + return 0;
> +}
> +
> +static int rockchip_usb3phy_exit(struct phy *phy)
> +{
> + struct rockchip_usb3phy_port *port = phy_get_drvdata(phy);
> + struct rockchip_usb3phy *usb3phy = dev_get_drvdata(phy->dev.parent);
> +
> + dev_dbg(usb3phy->dev, "usb3phy_shutdown\n");
> + rockchip_usb3phy_reset(usb3phy, true, port->type);
> +
> + return 0;
> +}
> +
> +static const struct phy_ops rockchip_usb3phy_ops = {
> + .init = rockchip_usb3phy_init,
> + .exit = rockchip_usb3phy_exit,
> + .owner = THIS_MODULE,
> +};
> +
> +static const struct regmap_config rockchip_usb3phy_utmi_port_regmap_config = {
> + .reg_bits = 32,
> + .val_bits = 32,
> + .reg_stride = 4,
> + .max_register = 0x400,
> + .cache_type = REGCACHE_NONE,
> + .fast_io = true,
> + .name = "utmi-port",
> +};
> +
> +static const struct regmap_config rockchip_usb3phy_pipe_port_regmap_config = {
> + .reg_bits = 32,
> + .val_bits = 32,
> + .reg_stride = 4,
> + .max_register = 0x400,
> + .cache_type = REGCACHE_NONE,
> + .fast_io = true,
> + .name = "pipe-port",
> +};
> +
> +static const struct regmap_config rockchip_usb3phy_regmap_config = {
> + .reg_bits = 32,
> + .val_bits = 32,
> + .reg_stride = 4,
> + .max_register = 0x400,
> + .write_flag_mask = REG_WRITE_MASK,
> + .cache_type = REGCACHE_NONE,
> + .fast_io = true,
> +};
> +
> +static int rockchip_usb3phy_probe(struct platform_device *pdev)
> +{
> + struct device *dev = &pdev->dev;
> + struct device_node *np = dev->of_node;
> + struct device_node *child_np;
> + struct phy_provider *provider;
> + struct rockchip_usb3phy *usb3phy;
> + const struct regmap_config regmap_config = rockchip_usb3phy_regmap_config;
> + void __iomem *base;
> + int i, ret;
> +
> + dev_dbg(dev, "Probe usb3phy main block\n");
> + usb3phy = devm_kzalloc(dev, sizeof(*usb3phy), GFP_KERNEL);
> + if (!usb3phy)
> + return -ENOMEM;
> +
> + ret = rockchip_usb3phy_parse_dt(usb3phy, dev);
> + if (ret) {
> + dev_err(dev, "parse dt failed %i\n", ret);
return dev_err_probe()
And do not print errors twice.
> + return ret;
> +
> + /* take apb interface out of reset */
> + reset_control_deassert(usb3phy->utmi_apb_rst);
> + reset_control_deassert(usb3phy->pipe_apb_rst);
> +
> + /* enable usb3phy rx detection to fix disconnection issues */
> + regmap_write(usb3phy->regmap, USB3PHY_WAKEUP_CON_REG,
> + (USB3_RXDET_EN | (USB3_RXDET_EN << REG_WRITE_SHIFT)));
> +
> + dev_dbg(dev, "Completed usb3phy core probe\n");
Drop.
> +
> + /* probe the actual ports */
> + i = 0;
> + for_each_available_child_of_node(np, child_np) {
> + const struct regmap_config *regmap_port_config;
> + struct rockchip_usb3phy_port *port = &usb3phy->ports[i];
> + struct phy *phy;
> +
> + if (of_node_name_eq(child_np, "utmi-port")) {
Why are you comparing node names, if you decided to put there compatibles?
Decide on one method, but wait for full DT review.
> + port->type = USB3PHY_TYPE_USB2;
> + regmap_port_config = &rockchip_usb3phy_utmi_port_regmap_config;
> + } else if (of_node_name_eq(child_np, "pipe-port")) {
> + port->type = USB3PHY_TYPE_USB3;
> + regmap_port_config = &rockchip_usb3phy_pipe_port_regmap_config;
> + } else {
> + dev_err(dev, "unknown child node port type %s\n", child_np->name);
> + goto err_port;
> + }
> +
> + base = devm_of_iomap(dev, child_np, 0, NULL);
> + if (IS_ERR(base)) {
> + dev_err(dev, "failed port ioremap\n");
> + ret = PTR_ERR(base);
> + goto err_port;
> + }
> +
> + port->regmap = devm_regmap_init_mmio(dev, base, regmap_port_config);
> + if (IS_ERR(port->regmap)) {
> + dev_err(dev, "regmap init failed\n");
> + ret = PTR_ERR(port->regmap);
> + goto err_port;
> + }
> +
> + phy = devm_phy_create(dev, child_np, &rockchip_usb3phy_ops);
> + if (IS_ERR(phy)) {
> + dev_err_probe(dev, PTR_ERR(phy), "failed to create phy\n");
> + ret = PTR_ERR(phy);
Just read how dev_err_probe() works. The syntax is:
ret = dev_err_probe.
> + goto err_port;
> + }
> +
> + port->phy = phy;
> + phy_set_drvdata(port->phy, port);
> +
> + /* to prevent out of boundary */
> + if (++i >= USB3PHY_TYPE_MAX) {
> + of_node_put(child_np);
> + break;
> + }
> +
> + dev_info(dev, "Completed usb3phy %s port init\n", child_np->name);
Drop, not really helping.
Best regards,
Krzysztof
WARNING: multiple messages have this Message-ID (diff)
From: Krzysztof Kozlowski <krzk@kernel.org>
To: Peter Geis <pgwipeout@gmail.com>, Heiko Stuebner <heiko@sntech.de>
Cc: Kishon Vijay Abraham I <kishon@kernel.org>,
Algea Cao <algea.cao@rock-chips.com>,
linux-kernel@vger.kernel.org, Arnd Bergmann <arnd@arndb.de>,
frank.wang@rock-chips.com, william.wu@rock-chips.com,
kever.yang@rock-chips.com, linux-phy@lists.infradead.org,
Sebastian Reichel <sebastian.reichel@collabora.com>,
linux-rockchip@lists.infradead.org, Vinod Koul <vkoul@kernel.org>,
Zhang Yubing <yubing.zhang@rock-chips.com>,
Philipp Zabel <p.zabel@pengutronix.de>,
zyw@rock-chips.com, wulf@rock-chips.com,
linux-arm-kernel@lists.infradead.org
Subject: Re: [RFC PATCH v1 3/6] phy: rockchip: add driver for rk3328 usb3 phy
Date: Thu, 16 Jan 2025 13:59:38 +0100 [thread overview]
Message-ID: <87001334-5a37-4fba-b08c-3679fb556f83@kernel.org> (raw)
In-Reply-To: <20250115012628.1035928-4-pgwipeout@gmail.com>
On 15/01/2025 02:26, Peter Geis wrote:
> The rk3328 has a combined usb2 and usb3 phy block for the usb3 dwc
> interface. The implementation up until now has been bugged, with
> multiple issues ranging from disconnect detection failures to low
> performance. This driver fixes the majority of the original issues and
> allows better performance for the rk3328 usb3 port.
>
> This driver sources data from multiple sources, including the rk3328
> trm, the rk3228h trm, emails from Rockchip, and both the 4.4 and 5.10
> downstream drivers. The current implementation allows for basic bring up
> of the phy block and fixes the detection issues. Interrupts are enabled,
> but currently only used for debugging. Features missing currently are
> power management, OTG handling, board specific tuning, regulator control,
>
> Currently the only known bugs are a AX88179 usb3 gigabit adapter crashes
> when operating at usb3 speeds and transmitting large amounts of data and
> full disconnection detections may be slower than expected (~5-10 seconds).
>
> Signed-off-by: Peter Geis <pgwipeout@gmail.com>
> ---
...
> +}
> +
> +static int rockchip_usb3phy_parse_dt(struct rockchip_usb3phy *usb3phy, struct device *dev)
> +{
> + int ret;
> +
> + usb3phy->clk_pipe = devm_clk_get(dev, "usb3phy-pipe");
> + if (IS_ERR(usb3phy->clk_pipe)) {
> + dev_err(dev, "could not get usb3phy pipe clock\n");
Syntax is always:
return dev_err_probe
> + return PTR_ERR(usb3phy->clk_pipe);
> + }
> +
> + usb3phy->clk_otg = devm_clk_get(dev, "usb3phy-otg");
> + if (IS_ERR(usb3phy->clk_otg)) {
> + dev_err(dev, "could not get usb3phy otg clock\n");
> + return PTR_ERR(usb3phy->clk_otg);
> + }
> +
> + usb3phy->clk_ref = devm_clk_get(dev, "refclk-usb3otg");
> + if (IS_ERR(usb3phy->clk_ref)) {
> + dev_err(dev, "could not get usb3phy ref clock\n");
> + return PTR_ERR(usb3phy->clk_ref);
> + }
> +
> + usb3phy->u2por_rst = devm_reset_control_get(dev, "usb3phy-u2-por");
> + if (IS_ERR(usb3phy->u2por_rst)) {
> + dev_err(dev, "no usb3phy-u2-por reset control found\n");
> + return PTR_ERR(usb3phy->u2por_rst);
> + }
> +
> + usb3phy->u3por_rst = devm_reset_control_get(dev, "usb3phy-u3-por");
> + if (IS_ERR(usb3phy->u3por_rst)) {
> + dev_err(dev, "no usb3phy-u3-por reset control found\n");
> + return PTR_ERR(usb3phy->u3por_rst);
> + }
> +
> + usb3phy->pipe_rst = devm_reset_control_get(dev, "usb3phy-pipe-mac");
> + if (IS_ERR(usb3phy->pipe_rst)) {
> + dev_err(dev, "no usb3phy_pipe_mac reset control found\n");
> + return PTR_ERR(usb3phy->pipe_rst);
> + }
> +
> + usb3phy->utmi_rst = devm_reset_control_get(dev, "usb3phy-utmi-mac");
> + if (IS_ERR(usb3phy->utmi_rst)) {
> + dev_err(dev, "no usb3phy-utmi-mac reset control found\n");
> + return PTR_ERR(usb3phy->utmi_rst);
> + }
> +
> + usb3phy->pipe_apb_rst = devm_reset_control_get(dev, "usb3phy-pipe-apb");
> + if (IS_ERR(usb3phy->pipe_apb_rst)) {
> + dev_err(dev, "no usb3phy-pipe-apb reset control found\n");
> + return PTR_ERR(usb3phy->pipe_apb_rst);
> + }
> +
> + usb3phy->utmi_apb_rst = devm_reset_control_get(dev, "usb3phy-utmi-apb");
> + if (IS_ERR(usb3phy->utmi_apb_rst)) {
> + dev_err(dev, "no usb3phy-utmi-apb reset control found\n");
> + return PTR_ERR(usb3phy->utmi_apb_rst);
> + }
> +
> + usb3phy->ls_irq = of_irq_get_byname(dev->of_node, "linestate");
> + if (usb3phy->ls_irq < 0) {
> + dev_err(dev, "no linestate irq provided\n");
> + return usb3phy->ls_irq;
> + }
> +
> + ret = devm_request_threaded_irq(dev, usb3phy->ls_irq, NULL, rockchip_usb3phy_linestate_irq,
> + IRQF_ONESHOT, "rockchip_usb3phy_ls", usb3phy);
> + if (ret) {
> + dev_err(dev, "failed to request linestate irq handle\n");
> + return ret;
> + }
> +
> + usb3phy->bvalid_irq = of_irq_get_byname(dev->of_node, "bvalid");
> + if (usb3phy->bvalid_irq < 0) {
> + dev_err(dev, "no bvalid irq provided\n");
> + return usb3phy->bvalid_irq;
> + }
> +
> + ret = devm_request_threaded_irq(dev, usb3phy->bvalid_irq, NULL, rockchip_usb3phy_bvalid_irq,
> + IRQF_ONESHOT, "rockchip_usb3phy_bvalid", usb3phy);
> + if (ret) {
> + dev_err(dev, "failed to request bvalid irq handle\n");
> + return ret;
> + }
> +
> + usb3phy->id_irq = of_irq_get_byname(dev->of_node, "id");
> + if (usb3phy->id_irq < 0) {
> + dev_err(dev, "no id irq provided\n");
> + return usb3phy->id_irq;
> + }
> +
> + ret = devm_request_threaded_irq(dev, usb3phy->id_irq, NULL, rockchip_usb3phy_id_irq,
> + IRQF_ONESHOT, "rockchip_usb3phy-id", usb3phy);
> + if (ret) {
> + dev_err(dev, "failed to request id irq handle\n");
> + return ret;
> + }
> +
> + usb3phy->rxdet_irq = of_irq_get_byname(dev->of_node, "rxdet");
> + if (usb3phy->rxdet_irq < 0) {
> + dev_err(dev, "no rxdet irq provided\n");
> + return usb3phy->rxdet_irq;
> + }
> +
> + ret = devm_request_threaded_irq(dev, usb3phy->rxdet_irq, NULL, rockchip_usb3phy_rxdet_irq,
> + IRQF_ONESHOT, "rockchip_usb3phy-rxdet", usb3phy);
> + if (ret) {
> + dev_err(dev, "failed to request rxdet irq handle\n");
> + return ret;
> + }
> +
> + return 0;
> +}
> +
> +static int rockchip_usb3phy_exit(struct phy *phy)
> +{
> + struct rockchip_usb3phy_port *port = phy_get_drvdata(phy);
> + struct rockchip_usb3phy *usb3phy = dev_get_drvdata(phy->dev.parent);
> +
> + dev_dbg(usb3phy->dev, "usb3phy_shutdown\n");
> + rockchip_usb3phy_reset(usb3phy, true, port->type);
> +
> + return 0;
> +}
> +
> +static const struct phy_ops rockchip_usb3phy_ops = {
> + .init = rockchip_usb3phy_init,
> + .exit = rockchip_usb3phy_exit,
> + .owner = THIS_MODULE,
> +};
> +
> +static const struct regmap_config rockchip_usb3phy_utmi_port_regmap_config = {
> + .reg_bits = 32,
> + .val_bits = 32,
> + .reg_stride = 4,
> + .max_register = 0x400,
> + .cache_type = REGCACHE_NONE,
> + .fast_io = true,
> + .name = "utmi-port",
> +};
> +
> +static const struct regmap_config rockchip_usb3phy_pipe_port_regmap_config = {
> + .reg_bits = 32,
> + .val_bits = 32,
> + .reg_stride = 4,
> + .max_register = 0x400,
> + .cache_type = REGCACHE_NONE,
> + .fast_io = true,
> + .name = "pipe-port",
> +};
> +
> +static const struct regmap_config rockchip_usb3phy_regmap_config = {
> + .reg_bits = 32,
> + .val_bits = 32,
> + .reg_stride = 4,
> + .max_register = 0x400,
> + .write_flag_mask = REG_WRITE_MASK,
> + .cache_type = REGCACHE_NONE,
> + .fast_io = true,
> +};
> +
> +static int rockchip_usb3phy_probe(struct platform_device *pdev)
> +{
> + struct device *dev = &pdev->dev;
> + struct device_node *np = dev->of_node;
> + struct device_node *child_np;
> + struct phy_provider *provider;
> + struct rockchip_usb3phy *usb3phy;
> + const struct regmap_config regmap_config = rockchip_usb3phy_regmap_config;
> + void __iomem *base;
> + int i, ret;
> +
> + dev_dbg(dev, "Probe usb3phy main block\n");
> + usb3phy = devm_kzalloc(dev, sizeof(*usb3phy), GFP_KERNEL);
> + if (!usb3phy)
> + return -ENOMEM;
> +
> + ret = rockchip_usb3phy_parse_dt(usb3phy, dev);
> + if (ret) {
> + dev_err(dev, "parse dt failed %i\n", ret);
return dev_err_probe()
And do not print errors twice.
> + return ret;
> +
> + /* take apb interface out of reset */
> + reset_control_deassert(usb3phy->utmi_apb_rst);
> + reset_control_deassert(usb3phy->pipe_apb_rst);
> +
> + /* enable usb3phy rx detection to fix disconnection issues */
> + regmap_write(usb3phy->regmap, USB3PHY_WAKEUP_CON_REG,
> + (USB3_RXDET_EN | (USB3_RXDET_EN << REG_WRITE_SHIFT)));
> +
> + dev_dbg(dev, "Completed usb3phy core probe\n");
Drop.
> +
> + /* probe the actual ports */
> + i = 0;
> + for_each_available_child_of_node(np, child_np) {
> + const struct regmap_config *regmap_port_config;
> + struct rockchip_usb3phy_port *port = &usb3phy->ports[i];
> + struct phy *phy;
> +
> + if (of_node_name_eq(child_np, "utmi-port")) {
Why are you comparing node names, if you decided to put there compatibles?
Decide on one method, but wait for full DT review.
> + port->type = USB3PHY_TYPE_USB2;
> + regmap_port_config = &rockchip_usb3phy_utmi_port_regmap_config;
> + } else if (of_node_name_eq(child_np, "pipe-port")) {
> + port->type = USB3PHY_TYPE_USB3;
> + regmap_port_config = &rockchip_usb3phy_pipe_port_regmap_config;
> + } else {
> + dev_err(dev, "unknown child node port type %s\n", child_np->name);
> + goto err_port;
> + }
> +
> + base = devm_of_iomap(dev, child_np, 0, NULL);
> + if (IS_ERR(base)) {
> + dev_err(dev, "failed port ioremap\n");
> + ret = PTR_ERR(base);
> + goto err_port;
> + }
> +
> + port->regmap = devm_regmap_init_mmio(dev, base, regmap_port_config);
> + if (IS_ERR(port->regmap)) {
> + dev_err(dev, "regmap init failed\n");
> + ret = PTR_ERR(port->regmap);
> + goto err_port;
> + }
> +
> + phy = devm_phy_create(dev, child_np, &rockchip_usb3phy_ops);
> + if (IS_ERR(phy)) {
> + dev_err_probe(dev, PTR_ERR(phy), "failed to create phy\n");
> + ret = PTR_ERR(phy);
Just read how dev_err_probe() works. The syntax is:
ret = dev_err_probe.
> + goto err_port;
> + }
> +
> + port->phy = phy;
> + phy_set_drvdata(port->phy, port);
> +
> + /* to prevent out of boundary */
> + if (++i >= USB3PHY_TYPE_MAX) {
> + of_node_put(child_np);
> + break;
> + }
> +
> + dev_info(dev, "Completed usb3phy %s port init\n", child_np->name);
Drop, not really helping.
Best regards,
Krzysztof
_______________________________________________
Linux-rockchip mailing list
Linux-rockchip@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-rockchip
WARNING: multiple messages have this Message-ID (diff)
From: Krzysztof Kozlowski <krzk@kernel.org>
To: Peter Geis <pgwipeout@gmail.com>, Heiko Stuebner <heiko@sntech.de>
Cc: zyw@rock-chips.com, kever.yang@rock-chips.com,
frank.wang@rock-chips.com, william.wu@rock-chips.com,
wulf@rock-chips.com, linux-rockchip@lists.infradead.org,
Algea Cao <algea.cao@rock-chips.com>,
Arnd Bergmann <arnd@arndb.de>,
Cristian Ciocaltea <cristian.ciocaltea@collabora.com>,
Kishon Vijay Abraham I <kishon@kernel.org>,
Philipp Zabel <p.zabel@pengutronix.de>,
Sebastian Reichel <sebastian.reichel@collabora.com>,
Vinod Koul <vkoul@kernel.org>,
Zhang Yubing <yubing.zhang@rock-chips.com>,
linux-arm-kernel@lists.infradead.org,
linux-kernel@vger.kernel.org, linux-phy@lists.infradead.org
Subject: Re: [RFC PATCH v1 3/6] phy: rockchip: add driver for rk3328 usb3 phy
Date: Thu, 16 Jan 2025 13:59:38 +0100 [thread overview]
Message-ID: <87001334-5a37-4fba-b08c-3679fb556f83@kernel.org> (raw)
In-Reply-To: <20250115012628.1035928-4-pgwipeout@gmail.com>
On 15/01/2025 02:26, Peter Geis wrote:
> The rk3328 has a combined usb2 and usb3 phy block for the usb3 dwc
> interface. The implementation up until now has been bugged, with
> multiple issues ranging from disconnect detection failures to low
> performance. This driver fixes the majority of the original issues and
> allows better performance for the rk3328 usb3 port.
>
> This driver sources data from multiple sources, including the rk3328
> trm, the rk3228h trm, emails from Rockchip, and both the 4.4 and 5.10
> downstream drivers. The current implementation allows for basic bring up
> of the phy block and fixes the detection issues. Interrupts are enabled,
> but currently only used for debugging. Features missing currently are
> power management, OTG handling, board specific tuning, regulator control,
>
> Currently the only known bugs are a AX88179 usb3 gigabit adapter crashes
> when operating at usb3 speeds and transmitting large amounts of data and
> full disconnection detections may be slower than expected (~5-10 seconds).
>
> Signed-off-by: Peter Geis <pgwipeout@gmail.com>
> ---
...
> +}
> +
> +static int rockchip_usb3phy_parse_dt(struct rockchip_usb3phy *usb3phy, struct device *dev)
> +{
> + int ret;
> +
> + usb3phy->clk_pipe = devm_clk_get(dev, "usb3phy-pipe");
> + if (IS_ERR(usb3phy->clk_pipe)) {
> + dev_err(dev, "could not get usb3phy pipe clock\n");
Syntax is always:
return dev_err_probe
> + return PTR_ERR(usb3phy->clk_pipe);
> + }
> +
> + usb3phy->clk_otg = devm_clk_get(dev, "usb3phy-otg");
> + if (IS_ERR(usb3phy->clk_otg)) {
> + dev_err(dev, "could not get usb3phy otg clock\n");
> + return PTR_ERR(usb3phy->clk_otg);
> + }
> +
> + usb3phy->clk_ref = devm_clk_get(dev, "refclk-usb3otg");
> + if (IS_ERR(usb3phy->clk_ref)) {
> + dev_err(dev, "could not get usb3phy ref clock\n");
> + return PTR_ERR(usb3phy->clk_ref);
> + }
> +
> + usb3phy->u2por_rst = devm_reset_control_get(dev, "usb3phy-u2-por");
> + if (IS_ERR(usb3phy->u2por_rst)) {
> + dev_err(dev, "no usb3phy-u2-por reset control found\n");
> + return PTR_ERR(usb3phy->u2por_rst);
> + }
> +
> + usb3phy->u3por_rst = devm_reset_control_get(dev, "usb3phy-u3-por");
> + if (IS_ERR(usb3phy->u3por_rst)) {
> + dev_err(dev, "no usb3phy-u3-por reset control found\n");
> + return PTR_ERR(usb3phy->u3por_rst);
> + }
> +
> + usb3phy->pipe_rst = devm_reset_control_get(dev, "usb3phy-pipe-mac");
> + if (IS_ERR(usb3phy->pipe_rst)) {
> + dev_err(dev, "no usb3phy_pipe_mac reset control found\n");
> + return PTR_ERR(usb3phy->pipe_rst);
> + }
> +
> + usb3phy->utmi_rst = devm_reset_control_get(dev, "usb3phy-utmi-mac");
> + if (IS_ERR(usb3phy->utmi_rst)) {
> + dev_err(dev, "no usb3phy-utmi-mac reset control found\n");
> + return PTR_ERR(usb3phy->utmi_rst);
> + }
> +
> + usb3phy->pipe_apb_rst = devm_reset_control_get(dev, "usb3phy-pipe-apb");
> + if (IS_ERR(usb3phy->pipe_apb_rst)) {
> + dev_err(dev, "no usb3phy-pipe-apb reset control found\n");
> + return PTR_ERR(usb3phy->pipe_apb_rst);
> + }
> +
> + usb3phy->utmi_apb_rst = devm_reset_control_get(dev, "usb3phy-utmi-apb");
> + if (IS_ERR(usb3phy->utmi_apb_rst)) {
> + dev_err(dev, "no usb3phy-utmi-apb reset control found\n");
> + return PTR_ERR(usb3phy->utmi_apb_rst);
> + }
> +
> + usb3phy->ls_irq = of_irq_get_byname(dev->of_node, "linestate");
> + if (usb3phy->ls_irq < 0) {
> + dev_err(dev, "no linestate irq provided\n");
> + return usb3phy->ls_irq;
> + }
> +
> + ret = devm_request_threaded_irq(dev, usb3phy->ls_irq, NULL, rockchip_usb3phy_linestate_irq,
> + IRQF_ONESHOT, "rockchip_usb3phy_ls", usb3phy);
> + if (ret) {
> + dev_err(dev, "failed to request linestate irq handle\n");
> + return ret;
> + }
> +
> + usb3phy->bvalid_irq = of_irq_get_byname(dev->of_node, "bvalid");
> + if (usb3phy->bvalid_irq < 0) {
> + dev_err(dev, "no bvalid irq provided\n");
> + return usb3phy->bvalid_irq;
> + }
> +
> + ret = devm_request_threaded_irq(dev, usb3phy->bvalid_irq, NULL, rockchip_usb3phy_bvalid_irq,
> + IRQF_ONESHOT, "rockchip_usb3phy_bvalid", usb3phy);
> + if (ret) {
> + dev_err(dev, "failed to request bvalid irq handle\n");
> + return ret;
> + }
> +
> + usb3phy->id_irq = of_irq_get_byname(dev->of_node, "id");
> + if (usb3phy->id_irq < 0) {
> + dev_err(dev, "no id irq provided\n");
> + return usb3phy->id_irq;
> + }
> +
> + ret = devm_request_threaded_irq(dev, usb3phy->id_irq, NULL, rockchip_usb3phy_id_irq,
> + IRQF_ONESHOT, "rockchip_usb3phy-id", usb3phy);
> + if (ret) {
> + dev_err(dev, "failed to request id irq handle\n");
> + return ret;
> + }
> +
> + usb3phy->rxdet_irq = of_irq_get_byname(dev->of_node, "rxdet");
> + if (usb3phy->rxdet_irq < 0) {
> + dev_err(dev, "no rxdet irq provided\n");
> + return usb3phy->rxdet_irq;
> + }
> +
> + ret = devm_request_threaded_irq(dev, usb3phy->rxdet_irq, NULL, rockchip_usb3phy_rxdet_irq,
> + IRQF_ONESHOT, "rockchip_usb3phy-rxdet", usb3phy);
> + if (ret) {
> + dev_err(dev, "failed to request rxdet irq handle\n");
> + return ret;
> + }
> +
> + return 0;
> +}
> +
> +static int rockchip_usb3phy_exit(struct phy *phy)
> +{
> + struct rockchip_usb3phy_port *port = phy_get_drvdata(phy);
> + struct rockchip_usb3phy *usb3phy = dev_get_drvdata(phy->dev.parent);
> +
> + dev_dbg(usb3phy->dev, "usb3phy_shutdown\n");
> + rockchip_usb3phy_reset(usb3phy, true, port->type);
> +
> + return 0;
> +}
> +
> +static const struct phy_ops rockchip_usb3phy_ops = {
> + .init = rockchip_usb3phy_init,
> + .exit = rockchip_usb3phy_exit,
> + .owner = THIS_MODULE,
> +};
> +
> +static const struct regmap_config rockchip_usb3phy_utmi_port_regmap_config = {
> + .reg_bits = 32,
> + .val_bits = 32,
> + .reg_stride = 4,
> + .max_register = 0x400,
> + .cache_type = REGCACHE_NONE,
> + .fast_io = true,
> + .name = "utmi-port",
> +};
> +
> +static const struct regmap_config rockchip_usb3phy_pipe_port_regmap_config = {
> + .reg_bits = 32,
> + .val_bits = 32,
> + .reg_stride = 4,
> + .max_register = 0x400,
> + .cache_type = REGCACHE_NONE,
> + .fast_io = true,
> + .name = "pipe-port",
> +};
> +
> +static const struct regmap_config rockchip_usb3phy_regmap_config = {
> + .reg_bits = 32,
> + .val_bits = 32,
> + .reg_stride = 4,
> + .max_register = 0x400,
> + .write_flag_mask = REG_WRITE_MASK,
> + .cache_type = REGCACHE_NONE,
> + .fast_io = true,
> +};
> +
> +static int rockchip_usb3phy_probe(struct platform_device *pdev)
> +{
> + struct device *dev = &pdev->dev;
> + struct device_node *np = dev->of_node;
> + struct device_node *child_np;
> + struct phy_provider *provider;
> + struct rockchip_usb3phy *usb3phy;
> + const struct regmap_config regmap_config = rockchip_usb3phy_regmap_config;
> + void __iomem *base;
> + int i, ret;
> +
> + dev_dbg(dev, "Probe usb3phy main block\n");
> + usb3phy = devm_kzalloc(dev, sizeof(*usb3phy), GFP_KERNEL);
> + if (!usb3phy)
> + return -ENOMEM;
> +
> + ret = rockchip_usb3phy_parse_dt(usb3phy, dev);
> + if (ret) {
> + dev_err(dev, "parse dt failed %i\n", ret);
return dev_err_probe()
And do not print errors twice.
> + return ret;
> +
> + /* take apb interface out of reset */
> + reset_control_deassert(usb3phy->utmi_apb_rst);
> + reset_control_deassert(usb3phy->pipe_apb_rst);
> +
> + /* enable usb3phy rx detection to fix disconnection issues */
> + regmap_write(usb3phy->regmap, USB3PHY_WAKEUP_CON_REG,
> + (USB3_RXDET_EN | (USB3_RXDET_EN << REG_WRITE_SHIFT)));
> +
> + dev_dbg(dev, "Completed usb3phy core probe\n");
Drop.
> +
> + /* probe the actual ports */
> + i = 0;
> + for_each_available_child_of_node(np, child_np) {
> + const struct regmap_config *regmap_port_config;
> + struct rockchip_usb3phy_port *port = &usb3phy->ports[i];
> + struct phy *phy;
> +
> + if (of_node_name_eq(child_np, "utmi-port")) {
Why are you comparing node names, if you decided to put there compatibles?
Decide on one method, but wait for full DT review.
> + port->type = USB3PHY_TYPE_USB2;
> + regmap_port_config = &rockchip_usb3phy_utmi_port_regmap_config;
> + } else if (of_node_name_eq(child_np, "pipe-port")) {
> + port->type = USB3PHY_TYPE_USB3;
> + regmap_port_config = &rockchip_usb3phy_pipe_port_regmap_config;
> + } else {
> + dev_err(dev, "unknown child node port type %s\n", child_np->name);
> + goto err_port;
> + }
> +
> + base = devm_of_iomap(dev, child_np, 0, NULL);
> + if (IS_ERR(base)) {
> + dev_err(dev, "failed port ioremap\n");
> + ret = PTR_ERR(base);
> + goto err_port;
> + }
> +
> + port->regmap = devm_regmap_init_mmio(dev, base, regmap_port_config);
> + if (IS_ERR(port->regmap)) {
> + dev_err(dev, "regmap init failed\n");
> + ret = PTR_ERR(port->regmap);
> + goto err_port;
> + }
> +
> + phy = devm_phy_create(dev, child_np, &rockchip_usb3phy_ops);
> + if (IS_ERR(phy)) {
> + dev_err_probe(dev, PTR_ERR(phy), "failed to create phy\n");
> + ret = PTR_ERR(phy);
Just read how dev_err_probe() works. The syntax is:
ret = dev_err_probe.
> + goto err_port;
> + }
> +
> + port->phy = phy;
> + phy_set_drvdata(port->phy, port);
> +
> + /* to prevent out of boundary */
> + if (++i >= USB3PHY_TYPE_MAX) {
> + of_node_put(child_np);
> + break;
> + }
> +
> + dev_info(dev, "Completed usb3phy %s port init\n", child_np->name);
Drop, not really helping.
Best regards,
Krzysztof
--
linux-phy mailing list
linux-phy@lists.infradead.org
https://lists.infradead.org/mailman/listinfo/linux-phy
next prev parent reply other threads:[~2025-01-16 12:59 UTC|newest]
Thread overview: 112+ messages / expand[flat|nested] mbox.gz Atom feed top
2025-01-15 1:26 [RFC PATCH v1 0/6] rockchip: add a functional usb3 phy driver for rk3328 Peter Geis
2025-01-15 1:26 ` Peter Geis
2025-01-15 1:26 ` Peter Geis
2025-01-15 1:26 ` [RFC PATCH v1 1/6] clk: rockchip: fix wrong clk_ref_usb3otg parent " Peter Geis
2025-01-15 1:26 ` Peter Geis
2025-01-15 1:26 ` [RFC PATCH v1 2/6] dt-bindings: phy: rockchip: add rk3328 usb3 phy Peter Geis
2025-01-15 1:26 ` Peter Geis
2025-01-15 1:26 ` Peter Geis
2025-01-16 13:08 ` Krzysztof Kozlowski
2025-01-16 13:08 ` Krzysztof Kozlowski
2025-01-16 13:08 ` Krzysztof Kozlowski
2025-01-16 13:32 ` Peter Geis
2025-01-16 13:32 ` Peter Geis
2025-01-16 13:32 ` Peter Geis
2025-01-16 13:59 ` Peter Geis
2025-01-16 13:59 ` Peter Geis
2025-01-16 13:59 ` Peter Geis
2025-01-18 9:06 ` Krzysztof Kozlowski
2025-01-18 9:06 ` Krzysztof Kozlowski
2025-01-18 9:06 ` Krzysztof Kozlowski
2025-01-15 1:26 ` [RFC PATCH v1 3/6] phy: rockchip: add driver for " Peter Geis
2025-01-15 1:26 ` Peter Geis
2025-01-15 1:26 ` Peter Geis
2025-01-15 11:24 ` Piotr Oniszczuk
2025-01-15 11:24 ` Piotr Oniszczuk
2025-01-15 11:24 ` Piotr Oniszczuk
2025-01-16 14:09 ` Peter Geis
2025-01-16 14:09 ` Peter Geis
2025-01-16 14:09 ` Peter Geis
2025-01-16 12:59 ` Krzysztof Kozlowski [this message]
2025-01-16 12:59 ` Krzysztof Kozlowski
2025-01-16 12:59 ` Krzysztof Kozlowski
2025-01-16 13:14 ` Peter Geis
2025-01-16 13:14 ` Peter Geis
2025-01-16 13:14 ` Peter Geis
2025-01-16 15:26 ` Diederik de Haas
2025-01-16 15:26 ` Diederik de Haas
2025-01-16 15:26 ` Diederik de Haas
2025-01-16 15:57 ` Peter Geis
2025-01-16 15:57 ` Peter Geis
2025-01-16 15:57 ` Peter Geis
2025-01-15 1:26 ` [RFC PATCH v1 4/6] arm64: dts: rockchip: add rk3328 usb3 phy node Peter Geis
2025-01-15 1:26 ` Peter Geis
2025-01-16 13:01 ` Krzysztof Kozlowski
2025-01-16 13:01 ` Krzysztof Kozlowski
2025-01-16 16:53 ` Diederik de Haas
2025-01-16 16:53 ` Diederik de Haas
2025-01-17 4:10 ` Dragan Simic
2025-01-17 4:10 ` Dragan Simic
2025-01-18 8:46 ` Krzysztof Kozlowski
2025-01-18 8:46 ` Krzysztof Kozlowski
2025-01-18 9:25 ` Dragan Simic
2025-01-18 9:25 ` Dragan Simic
2025-01-18 9:31 ` Krzysztof Kozlowski
2025-01-18 9:31 ` Krzysztof Kozlowski
2025-01-18 9:43 ` Dragan Simic
2025-01-18 9:43 ` Dragan Simic
2025-01-18 9:52 ` Krzysztof Kozlowski
2025-01-18 9:52 ` Krzysztof Kozlowski
2025-01-18 10:10 ` Dragan Simic
2025-01-18 10:10 ` Dragan Simic
2025-01-18 10:29 ` Krzysztof Kozlowski
2025-01-18 10:29 ` Krzysztof Kozlowski
2025-01-18 10:45 ` Dragan Simic
2025-01-18 10:45 ` Dragan Simic
2025-01-18 14:22 ` Peter Geis
2025-01-18 14:22 ` Peter Geis
2025-01-18 8:41 ` Krzysztof Kozlowski
2025-01-18 8:41 ` Krzysztof Kozlowski
2025-01-18 9:19 ` Krzysztof Kozlowski
2025-01-18 9:19 ` Krzysztof Kozlowski
2025-01-18 9:34 ` Dragan Simic
2025-01-18 9:34 ` Dragan Simic
2025-01-18 15:55 ` Diederik de Haas
2025-01-18 15:55 ` Diederik de Haas
2025-01-15 1:26 ` [RFC PATCH v1 5/6] arm64: dts: rockchip: enable the usb3 phy on rk3328-roc boards Peter Geis
2025-01-15 1:26 ` Peter Geis
2025-01-15 1:26 ` [RFC PATCH v1 6/6] arm64: dts: rockchip: enable the usb3 phy on remaining rk3328 boards Peter Geis
2025-01-15 1:26 ` Peter Geis
2025-01-15 11:22 ` [RFC PATCH v1 0/6] rockchip: add a functional usb3 phy driver for rk3328 Piotr Oniszczuk
2025-01-15 11:22 ` Piotr Oniszczuk
2025-01-15 11:22 ` Piotr Oniszczuk
2025-01-15 12:25 ` Peter Geis
2025-01-15 12:25 ` Peter Geis
2025-01-15 12:25 ` Peter Geis
2025-01-15 12:35 ` Piotr Oniszczuk
2025-01-15 12:35 ` Piotr Oniszczuk
2025-01-15 12:35 ` Piotr Oniszczuk
2025-01-15 13:15 ` Peter Geis
2025-01-15 13:15 ` Peter Geis
2025-01-15 13:15 ` Peter Geis
2025-01-15 13:25 ` Piotr Oniszczuk
2025-01-15 13:25 ` Piotr Oniszczuk
2025-01-15 13:25 ` Piotr Oniszczuk
2025-01-16 14:02 ` Peter Geis
2025-01-16 14:02 ` Peter Geis
2025-01-16 14:02 ` Peter Geis
2025-01-16 14:35 ` Piotr Oniszczuk
2025-01-16 14:35 ` Piotr Oniszczuk
2025-01-16 14:35 ` Piotr Oniszczuk
2025-01-16 16:00 ` Peter Geis
2025-01-16 16:00 ` Peter Geis
2025-01-16 16:00 ` Peter Geis
2025-01-18 9:08 ` Krzysztof Kozlowski
2025-01-18 9:08 ` Krzysztof Kozlowski
2025-01-18 9:08 ` Krzysztof Kozlowski
2025-01-18 14:35 ` Peter Geis
2025-01-18 14:35 ` Peter Geis
2025-01-18 14:35 ` Peter Geis
2025-02-26 19:49 ` (subset) " Heiko Stuebner
2025-02-26 19:49 ` Heiko Stuebner
2025-02-26 19:49 ` Heiko Stuebner
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=87001334-5a37-4fba-b08c-3679fb556f83@kernel.org \
--to=krzk@kernel.org \
--cc=algea.cao@rock-chips.com \
--cc=arnd@arndb.de \
--cc=cristian.ciocaltea@collabora.com \
--cc=frank.wang@rock-chips.com \
--cc=heiko@sntech.de \
--cc=kever.yang@rock-chips.com \
--cc=kishon@kernel.org \
--cc=linux-arm-kernel@lists.infradead.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-phy@lists.infradead.org \
--cc=linux-rockchip@lists.infradead.org \
--cc=p.zabel@pengutronix.de \
--cc=pgwipeout@gmail.com \
--cc=sebastian.reichel@collabora.com \
--cc=vkoul@kernel.org \
--cc=william.wu@rock-chips.com \
--cc=wulf@rock-chips.com \
--cc=yubing.zhang@rock-chips.com \
--cc=zyw@rock-chips.com \
/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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.