Re: [PATCH] usb: phy: bcm-ns-usb3: new driver for USB 3.0 PHY on Northstar

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



CC: bcm-kernel-feedback-list, Jon

Le 28/03/2016 14:59, Rafał Miłecki a écrit :
> Northstar is a family of SoCs used in home routers. They have USB 2.0
> and 3.0 controllers with PHYs that need to be properly initialized.
> This driver provides PHY init support in a generic way and can be bound
> with XHCI controller driver.
> 
> Signed-off-by: Rafał Miłecki <zajec5@xxxxxxxxx>
> ---
>  .../devicetree/bindings/usb/ns-usb3-phy.txt        |  14 ++
>  drivers/usb/phy/Kconfig                            |   8 +
>  drivers/usb/phy/Makefile                           |   1 +
>  drivers/usb/phy/phy-bcm-ns-usb3.c                  | 256 +++++++++++++++++++++
>  include/linux/bcma/bcma_driver_chipcommon.h        |   3 +
>  5 files changed, 282 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/usb/ns-usb3-phy.txt
>  create mode 100644 drivers/usb/phy/phy-bcm-ns-usb3.c
> 
> diff --git a/Documentation/devicetree/bindings/usb/ns-usb3-phy.txt b/Documentation/devicetree/bindings/usb/ns-usb3-phy.txt
> new file mode 100644
> index 0000000..ded03a9
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/usb/ns-usb3-phy.txt
> @@ -0,0 +1,14 @@
> +Driver for Broadcom Northstar USB 3.0 PHY
> +
> +Required properties:
> +- compatible: brcm,ns-usb3-phy
> +- bus: phandle of brcm,bus-axi
> +
> +To initialize USB 3.0 PHY driver needs to access various bus cores (devices).
> +This is why phandle to bcma bus is needed.
> +
> +Example:
> +	usb3-phy {
> +		compatible = "brcm,ns-usb3-phy";
> +		bus = <&axi>;
> +	};
> diff --git a/drivers/usb/phy/Kconfig b/drivers/usb/phy/Kconfig
> index c690474..aa28ea7 100644
> --- a/drivers/usb/phy/Kconfig
> +++ b/drivers/usb/phy/Kconfig
> @@ -18,6 +18,14 @@ config AB8500_USB
>  	  This transceiver supports high and full speed devices plus,
>  	  in host mode, low speed.
>  
> +config BCM_NS_USB3_PHY
> +	tristate "Broadcom Northstar USB 3.0 PHY Driver"
> +	depends on BCMA
> +	select USB_PHY
> +	help
> +	  Enable this to support USB 3.0 PHY connected to the USB controller on
> +	  bcma bus.
> +
>  config FSL_USB2_OTG
>  	bool "Freescale USB OTG Transceiver Driver"
>  	depends on USB_EHCI_FSL && USB_FSL_USB2 && USB_OTG_FSM && PM
> diff --git a/drivers/usb/phy/Makefile b/drivers/usb/phy/Makefile
> index b433e5d..5247572 100644
> --- a/drivers/usb/phy/Makefile
> +++ b/drivers/usb/phy/Makefile
> @@ -7,6 +7,7 @@ obj-$(CONFIG_OF)			+= of.o
>  # transceiver drivers, keep the list sorted
>  
>  obj-$(CONFIG_AB8500_USB)		+= phy-ab8500-usb.o
> +obj-$(CONFIG_BCM_NS_USB3_PHY)		+= phy-bcm-ns-usb3.o
>  obj-$(CONFIG_FSL_USB2_OTG)		+= phy-fsl-usb.o
>  obj-$(CONFIG_ISP1301_OMAP)		+= phy-isp1301-omap.o
>  obj-$(CONFIG_NOP_USB_XCEIV)		+= phy-generic.o
> diff --git a/drivers/usb/phy/phy-bcm-ns-usb3.c b/drivers/usb/phy/phy-bcm-ns-usb3.c
> new file mode 100644
> index 0000000..23c95f4
> --- /dev/null
> +++ b/drivers/usb/phy/phy-bcm-ns-usb3.c
> @@ -0,0 +1,256 @@
> +/*
> + * Broadcom Northstar USB 3.0 PHY Driver
> + *
> + * Copyright (C) 2016 Rafał Miłecki <zajec5@xxxxxxxxx>
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + *
> + */
> +
> +#include <linux/bcma/bcma.h>
> +#include <linux/module.h>
> +#include <linux/platform_device.h>
> +#include <linux/of_platform.h>
> +#include <linux/usb/otg.h>
> +#include <linux/slab.h>
> +#include <linux/delay.h>
> +#include <linux/err.h>
> +
> +#define BCM_NS_USB3_MII_MNG_TIMEOUT	1000	/* us */
> +
> +struct bcm_ns_usb3 {
> +	struct device *dev;
> +	struct bcma_bus *bus;
> +	struct bcma_device *core;
> +	struct usb_phy phy;
> +};
> +
> +static inline struct bcm_ns_usb3 *phy_to_usb3(struct usb_phy *phy)
> +{
> +	return container_of(phy, struct bcm_ns_usb3, phy);
> +}
> +
> +static bool bcm_ns_usb3_wait_reg(struct bcm_ns_usb3 *usb3, void __iomem *addr,
> +				 u32 mask, u32 value, int timeout)
> +{
> +	unsigned long deadline = jiffies + timeout;

We are mixing timeout in micro seconds with jiffies here, should that be
msecs_to_jiffies(timeout) instead?

> +	u32 val;
> +
> +	do {
> +		val = readl(addr);
> +		if ((val & mask) == value)
> +			return true;
> +		cpu_relax();
> +		udelay(10);

Delay + relax, why not a msleep() instead?

> +	} while (!time_after_eq(jiffies, deadline));
> +
> +	dev_err(usb3->dev, "Timeout waiting for register %p\n", addr);
> +
> +	return false;
> +}
> +
> +static inline bool bcm_ns_usb3_mii_mng_wait_idle(struct bcm_ns_usb3 *usb3)
> +{
> +	struct bcma_drv_cc_b *ccb = &usb3->bus->drv_cc_b;
> +
> +	return bcm_ns_usb3_wait_reg(usb3, ccb->mii + BCMA_CCB_MII_MNG_CTL,
> +				    0x0100, 0x0000,
> +				    BCM_NS_USB3_MII_MNG_TIMEOUT);
> +}
> +
> +static void bcm_ns_usb3_mii_mng_write32(struct bcm_ns_usb3 *usb3, u32 value)
> +{
> +	struct bcma_drv_cc_b *ccb = &usb3->bus->drv_cc_b;
> +
> +	bcm_ns_usb3_mii_mng_wait_idle(usb3);
> +
> +	iowrite32(value, ccb->mii + BCMA_CCB_MII_MNG_CMD_DATA);
> +}
> +
> +static void bcm_ns_usb3_phy_init_ns_bx(struct bcm_ns_usb3 *usb3)
> +{
> +	struct bcma_drv_cc_b *ccb = &usb3->bus->drv_cc_b;
> +
> +	/* Enable MDIO. Setting MDCDIV as 26  */
> +	iowrite32(0x0000009a, ccb->mii + BCMA_CCB_MII_MNG_CTL);
> +	udelay(2);
> +
> +	/* USB3 PLL Block */
> +	bcm_ns_usb3_mii_mng_write32(usb3, 0x587e8000);

We might want to make the first write check whether the MII bus was idle
or not, just in case?

> +
> +	/* Assert Ana_Pllseq start */
> +	bcm_ns_usb3_mii_mng_write32(usb3, 0x58061000);
> +
> +	/* Assert CML Divider ratio to 26 */
> +	bcm_ns_usb3_mii_mng_write32(usb3, 0x582a6400);
> +
> +	/* Asserting PLL Reset */
> +	bcm_ns_usb3_mii_mng_write32(usb3, 0x582ec000);
> +
> +	/* Deaaserting PLL Reset */
> +	bcm_ns_usb3_mii_mng_write32(usb3, 0x582e8000);
> +
> +	/* Waiting MII Mgt interface idle */
> +	bcm_ns_usb3_mii_mng_wait_idle(usb3);
> +
> +	/* Deasserting USB3 system reset */
> +	bcma_awrite32(usb3->core, BCMA_RESET_CTL, 0);
> +
> +	/* PLL frequency monitor enable */
> +	bcm_ns_usb3_mii_mng_write32(usb3, 0x58069000);
> +
> +	/* PIPE Block */
> +	bcm_ns_usb3_mii_mng_write32(usb3, 0x587e8060);
> +
> +	/* CMPMAX & CMPMINTH setting */
> +	bcm_ns_usb3_mii_mng_write32(usb3, 0x580af30d);
> +
> +	/* DEGLITCH MIN & MAX setting */
> +	bcm_ns_usb3_mii_mng_write32(usb3, 0x580e6302);
> +
> +	/* TXPMD block */
> +	bcm_ns_usb3_mii_mng_write32(usb3, 0x587e8040);
> +
> +	/* Enabling SSC */
> +	bcm_ns_usb3_mii_mng_write32(usb3, 0x58061003);
> +
> +	/* Waiting MII Mgt interface idle */
> +	bcm_ns_usb3_mii_mng_wait_idle(usb3);
> +}
> +
> +static void bcm_ns_usb3_phy_init_ns_ax(struct bcm_ns_usb3 *usb3)
> +{
> +	struct bcma_drv_cc_b *ccb = &usb3->bus->drv_cc_b;
> +
> +	/* Enable MDIO. Setting MDCDIV as 26  */
> +	iowrite32(0x0000009a, ccb->mii + BCMA_CCB_MII_MNG_CTL);
> +	udelay(2);
> +
> +	/* PLL30 block */
> +	bcm_ns_usb3_mii_mng_write32(usb3, 0x587e8000);
> +
> +	bcm_ns_usb3_mii_mng_write32(usb3, 0x582a6400);
> +
> +	bcm_ns_usb3_mii_mng_write32(usb3, 0x587e80e0);
> +
> +	bcm_ns_usb3_mii_mng_write32(usb3, 0x580a009c);
> +
> +	/* Enable SSC */
> +	bcm_ns_usb3_mii_mng_write32(usb3, 0x587e8040);
> +
> +	bcm_ns_usb3_mii_mng_write32(usb3, 0x580a21d3);
> +
> +	bcm_ns_usb3_mii_mng_write32(usb3, 0x58061003);
> +
> +	/* Waiting MII Mgt interface idle */
> +	bcm_ns_usb3_mii_mng_wait_idle(usb3);
> +
> +	/* Deasserting USB3 system reset */
> +	bcma_awrite32(usb3->core, BCMA_RESET_CTL, 0);
> +}
> +
> +static int bcm_ns_usb3_phy_init(struct usb_phy *phy)
> +{
> +	struct bcm_ns_usb3 *usb3 = phy_to_usb3(phy);
> +	struct bcma_chipinfo *chipinfo = &usb3->bus->chipinfo;
> +
> +	/* Perform USB3 system soft reset */
> +	bcma_awrite32(usb3->core, BCMA_RESET_CTL, BCMA_RESET_CTL_RESET);
> +
> +	if (chipinfo->id == BCMA_CHIP_ID_BCM53018 ||
> +	    (chipinfo->id == BCMA_CHIP_ID_BCM4707 && (chipinfo->rev == 4 || chipinfo->rev == 6)) ||
> +	    chipinfo->id == BCMA_CHIP_ID_BCM47094) {
> +		bcm_ns_usb3_phy_init_ns_bx(usb3);
> +	} else if (chipinfo->id == BCMA_CHIP_ID_BCM4707) {
> +		bcm_ns_usb3_phy_init_ns_ax(usb3);

We could propagate an error back to this function in case any of these
two fails because the bus is not idle?
-- 
Florian
--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html



[Index of Archives]     [Linux Media]     [Linux Input]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]     [Old Linux USB Devel Archive]

  Powered by Linux