Hi Balbi, > On Thu, Aug 09, 2012 at 08:04:44PM +0800, Yu Xu wrote: >> The driver supports phy_init and phy_shutdown functions to >> enable and disable phy for Marvell USB 3.0 controller. >> >> Signed-off-by: Yu Xu <yuxu@xxxxxxxxxxx> >> --- >> drivers/usb/phy/Kconfig | 8 + >> drivers/usb/phy/Makefile | 1 + >> drivers/usb/phy/mv_u3d_phy.c | 354 ++++++++++++++++++++++++++++++++++++++++++ >> drivers/usb/phy/mv_u3d_phy.h | 105 +++++++++++++ >> 4 files changed, 468 insertions(+) >> create mode 100644 drivers/usb/phy/mv_u3d_phy.c >> create mode 100644 drivers/usb/phy/mv_u3d_phy.h >> >> diff --git a/drivers/usb/phy/Kconfig b/drivers/usb/phy/Kconfig >> index e7cf84f..2838adb 100644 >> --- a/drivers/usb/phy/Kconfig >> +++ b/drivers/usb/phy/Kconfig >> @@ -15,3 +15,11 @@ config USB_ISP1301 >> >> To compile this driver as a module, choose M here: the >> module will be called isp1301. >> + >> +config MV_U3D_PHY >> + bool "Marvell USB 3.0 PHY controller Driver" >> + depends on USB_MV_U3D >> + select USB_OTG_UTILS >> + help >> + Enable this to support Marvell USB 3.0 phy controller for Marvell >> + SoC. >> diff --git a/drivers/usb/phy/Makefile b/drivers/usb/phy/Makefile >> index eca095b..cf38f08 100644 >> --- a/drivers/usb/phy/Makefile >> +++ b/drivers/usb/phy/Makefile >> @@ -5,3 +5,4 @@ >> ccflags-$(CONFIG_USB_DEBUG) := -DDEBUG >> >> obj-$(CONFIG_USB_ISP1301) += isp1301.o >> +obj-$(CONFIG_MV_U3D_PHY) += mv_u3d_phy.o >> diff --git a/drivers/usb/phy/mv_u3d_phy.c b/drivers/usb/phy/mv_u3d_phy.c >> new file mode 100644 >> index 0000000..99312e4 >> --- /dev/null >> +++ b/drivers/usb/phy/mv_u3d_phy.c >> @@ -0,0 +1,354 @@ >> +/* >> + * Copyright (C) 2011 Marvell International Ltd. All rights reserved. >> + * >> + * This program is free software; you can redistribute it and/or modify it >> + * under the terms and conditions of the GNU General Public License, >> + * version 2, as published by the Free Software Foundation. >> + */ >> + >> +#include <linux/module.h> >> +#include <linux/platform_device.h> >> +#include <linux/clk.h> >> +#include <linux/delay.h> >> +#include <linux/err.h> >> +#include <linux/io.h> >> +#include <linux/usb/otg.h> >> +#include <linux/platform_data/mv_usb.h> >> + >> +#include "mv_u3d_phy.h" >> + >> +/* >> + * struct mv_u3d_phy - transceiver driver state >> + * @phy: transceiver structure >> + * @dev: The parent device supplied to the probe function >> + * @clk: usb phy clock >> + * @base: usb phy register memory base >> + */ >> +struct mv_u3d_phy { >> + struct usb_phy phy; >> + struct mv_usb_platform_data *plat; >> + struct device *dev; >> + struct clk *clk; >> + void __iomem *base; >> +}; >> + >> +static u32 mv_u3d_phy_read(void __iomem *base, u32 reg) >> +{ >> + void __iomem *addr, *data; >> + >> + addr = base; >> + data = base + 0x4; >> + >> + writel_relaxed(reg, addr); >> + return readl_relaxed(data); >> +} >> + >> +static void mv_u3d_phy_set(void __iomem *base, u32 reg, u32 value) >> +{ >> + void __iomem *addr, *data; >> + u32 tmp; >> + >> + addr = base; >> + data = base + 0x4; >> + >> + writel_relaxed(reg, addr); >> + tmp = readl_relaxed(data); >> + tmp |= value; >> + writel_relaxed(tmp, data); >> +} >> + >> +static void mv_u3d_phy_clear(void __iomem *base, u32 reg, u32 value) >> +{ >> + void __iomem *addr, *data; >> + u32 tmp; >> + >> + addr = base; >> + data = base + 0x4; >> + >> + writel_relaxed(reg, addr); >> + tmp = readl_relaxed(data); >> + tmp &= ~value; >> + writel_relaxed(tmp, data); >> +} >> + >> +static void mv_u3d_phy_write(void __iomem *base, u32 reg, u32 value) >> +{ >> + void __iomem *addr, *data; >> + >> + addr = base; >> + data = base + 0x4; >> + >> + writel_relaxed(reg, addr); >> + writel_relaxed(value, data); >> +} >> + >> +static void mv_u3d_phy_reg_print(void __iomem *base, u32 reg) >> +{ >> + u32 data; >> + data = mv_u3d_phy_read(base, reg); >> + pr_debug("phy reg 0x%x: phy data 0x%x\n", reg, data); >> +} >> + >> +void mv_u3d_phy_shutdown(struct usb_phy *phy) >> +{ >> + struct mv_u3d_phy *mv_u3d_phy; >> + void __iomem *base; >> + u32 val; >> + >> + mv_u3d_phy = container_of(phy, struct mv_u3d_phy, phy); >> + base = mv_u3d_phy->base; >> + >> + /* Power down Reference Analog current, bit 15 >> + * Power down PLL, bit 14 >> + * Power down Receiver, bit 13 >> + * Power down Transmitter, bit 12 >> + * of USB3_POWER_PLL_CONTROL register >> + */ >> + val = mv_u3d_phy_read(base, USB3_POWER_PLL_CONTROL); >> + val &= ~(USB3_POWER_PLL_CONTROL_PU); >> + mv_u3d_phy_write(base, USB3_POWER_PLL_CONTROL, val); >> + >> + if (mv_u3d_phy->clk) >> + clk_disable(mv_u3d_phy->clk); >> +} >> + >> +static int mv_u3d_phy_init(struct usb_phy *phy) >> +{ >> + struct mv_u3d_phy *mv_u3d_phy; >> + void __iomem *base; >> + u32 val, count; >> + >> + /* enable usb3 phy */ >> + mv_u3d_phy = container_of(phy, struct mv_u3d_phy, phy); >> + >> + if (mv_u3d_phy->clk) >> + clk_enable(mv_u3d_phy->clk); >> + >> + base = mv_u3d_phy->base; >> + >> + val = mv_u3d_phy_read(base, USB3_POWER_PLL_CONTROL); >> + val &= ~(USB3_POWER_PLL_CONTROL_PU_MASK); >> + val |= 0xF << USB3_POWER_PLL_CONTROL_PU_SHIFT; >> + mv_u3d_phy_write(base, USB3_POWER_PLL_CONTROL, val); >> + udelay(100); >> + >> + mv_u3d_phy_write(base, USB3_RESET_CONTROL, >> + USB3_RESET_CONTROL_RESET_PIPE); >> + udelay(100); >> + >> + mv_u3d_phy_write(base, USB3_RESET_CONTROL, >> + USB3_RESET_CONTROL_RESET_PIPE >> + | USB3_RESET_CONTROL_RESET_PHY); >> + udelay(100); >> + >> + val = mv_u3d_phy_read(base, USB3_POWER_PLL_CONTROL); >> + val &= ~(USB3_POWER_PLL_CONTROL_REF_FREF_SEL_MASK >> + | USB3_POWER_PLL_CONTROL_PHY_MODE_MASK); >> + val |= (USB3_PLL_25MHZ << USB3_POWER_PLL_CONTROL_REF_FREF_SEL_SHIFT) >> + | (0x5 << USB3_POWER_PLL_CONTROL_PHY_MODE_SHIFT); >> + mv_u3d_phy_write(base, USB3_POWER_PLL_CONTROL, val); >> + udelay(100); >> + >> + mv_u3d_phy_clear(base, USB3_KVCO_CALI_CONTROL, >> + USB3_KVCO_CALI_CONTROL_USE_MAX_PLL_RATE_MASK); >> + udelay(100); >> + >> + val = mv_u3d_phy_read(base, USB3_SQUELCH_FFE); >> + val &= ~(USB3_SQUELCH_FFE_FFE_CAP_SEL_MASK >> + | USB3_SQUELCH_FFE_FFE_RES_SEL_MASK >> + | USB3_SQUELCH_FFE_SQ_THRESH_IN_MASK); >> + val |= ((0xD << USB3_SQUELCH_FFE_FFE_CAP_SEL_SHIFT) >> + | (0x7 << USB3_SQUELCH_FFE_FFE_RES_SEL_SHIFT) >> + | (0x8 << USB3_SQUELCH_FFE_SQ_THRESH_IN_SHIFT)); >> + mv_u3d_phy_write(base, USB3_SQUELCH_FFE, val); >> + udelay(100); >> + >> + val = mv_u3d_phy_read(base, USB3_GEN1_SET0); >> + val &= ~USB3_GEN1_SET0_G1_TX_SLEW_CTRL_EN_MASK; >> + val |= 1 << USB3_GEN1_SET0_G1_TX_EMPH_EN_SHIFT; >> + mv_u3d_phy_write(base, USB3_GEN1_SET0, val); >> + udelay(100); >> + >> + val = mv_u3d_phy_read(base, USB3_GEN2_SET0); >> + val &= ~(USB3_GEN2_SET0_G2_TX_AMP_MASK >> + | USB3_GEN2_SET0_G2_TX_EMPH_AMP_MASK >> + | USB3_GEN2_SET0_G2_TX_SLEW_CTRL_EN_MASK); >> + val |= ((0x14 << USB3_GEN2_SET0_G2_TX_AMP_SHIFT) >> + | (1 << USB3_GEN2_SET0_G2_TX_AMP_ADJ_SHIFT) >> + | (0xA << USB3_GEN2_SET0_G2_TX_EMPH_AMP_SHIFT) >> + | (1 << USB3_GEN2_SET0_G2_TX_EMPH_EN_SHIFT)); >> + mv_u3d_phy_write(base, USB3_GEN2_SET0, val); >> + udelay(100); >> + >> + mv_u3d_phy_read(base, USB3_TX_EMPPH); >> + val &= ~(USB3_TX_EMPPH_AMP_MASK >> + | USB3_TX_EMPPH_EN_MASK >> + | USB3_TX_EMPPH_AMP_FORCE_MASK >> + | USB3_TX_EMPPH_PAR1_MASK >> + | USB3_TX_EMPPH_PAR2_MASK); >> + val |= ((0xB << USB3_TX_EMPPH_AMP_SHIFT) >> + | (1 << USB3_TX_EMPPH_EN_SHIFT) >> + | (1 << USB3_TX_EMPPH_AMP_FORCE_SHIFT) >> + | (0x1C << USB3_TX_EMPPH_PAR1_SHIFT) >> + | (1 << USB3_TX_EMPPH_PAR2_SHIFT)); >> + >> + mv_u3d_phy_write(base, USB3_TX_EMPPH, val); >> + udelay(100); >> + >> + val = mv_u3d_phy_read(base, USB3_GEN2_SET1); >> + val &= ~(USB3_GEN2_SET1_G2_RX_SELMUPI_MASK >> + | USB3_GEN2_SET1_G2_RX_SELMUPF_MASK >> + | USB3_GEN2_SET1_G2_RX_SELMUFI_MASK >> + | USB3_GEN2_SET1_G2_RX_SELMUFF_MASK); >> + val |= ((1 << USB3_GEN2_SET1_G2_RX_SELMUPI_SHIFT) >> + | (1 << USB3_GEN2_SET1_G2_RX_SELMUPF_SHIFT) >> + | (1 << USB3_GEN2_SET1_G2_RX_SELMUFI_SHIFT) >> + | (1 << USB3_GEN2_SET1_G2_RX_SELMUFF_SHIFT)); >> + mv_u3d_phy_write(base, USB3_GEN2_SET1, val); >> + udelay(100); >> + >> + val = mv_u3d_phy_read(base, USB3_DIGITAL_LOOPBACK_EN); >> + val &= ~USB3_DIGITAL_LOOPBACK_EN_SEL_BITS_MASK; >> + val |= 1 << USB3_DIGITAL_LOOPBACK_EN_SEL_BITS_SHIFT; >> + mv_u3d_phy_write(base, USB3_DIGITAL_LOOPBACK_EN, val); >> + udelay(100); >> + >> + val = mv_u3d_phy_read(base, USB3_IMPEDANCE_TX_SSC); >> + val &= ~USB3_IMPEDANCE_TX_SSC_SSC_AMP_MASK; >> + val |= 0xC << USB3_IMPEDANCE_TX_SSC_SSC_AMP_SHIFT; >> + mv_u3d_phy_write(base, USB3_IMPEDANCE_TX_SSC, val); >> + udelay(100); >> + >> + val = mv_u3d_phy_read(base, USB3_IMPEDANCE_CALI_CTRL); >> + val &= ~USB3_IMPEDANCE_CALI_CTRL_IMP_CAL_THR_MASK; >> + val |= 0x4 << USB3_IMPEDANCE_CALI_CTRL_IMP_CAL_THR_SHIFT; >> + mv_u3d_phy_write(base, USB3_IMPEDANCE_CALI_CTRL, val); >> + udelay(100); >> + >> + val = mv_u3d_phy_read(base, USB3_PHY_ISOLATION_MODE); >> + val &= ~(USB3_PHY_ISOLATION_MODE_PHY_GEN_RX_MASK >> + | USB3_PHY_ISOLATION_MODE_PHY_GEN_TX_MASK >> + | USB3_PHY_ISOLATION_MODE_TX_DRV_IDLE_MASK); >> + val |= ((1 << USB3_PHY_ISOLATION_MODE_PHY_GEN_RX_SHIFT) >> + | (1 << USB3_PHY_ISOLATION_MODE_PHY_GEN_TX_SHIFT)); >> + mv_u3d_phy_write(base, USB3_PHY_ISOLATION_MODE, val); >> + udelay(100); >> + >> + val = mv_u3d_phy_read(base, USB3_TXDETRX); >> + val &= ~(USB3_TXDETRX_VTHSEL_MASK); >> + val |= 0x1 << USB3_TXDETRX_VTHSEL_SHIFT; >> + mv_u3d_phy_write(base, USB3_TXDETRX, val); >> + udelay(100); >> + >> + mv_u3d_phy_reg_print(base, USB3_KVCO_CALI_CONTROL); > > I'm not sure you really want this constantly on your driver, because it > introduces quite some overhead when you always need to readback the > register before printing. Couldn't you just move this out of the driver > and use perf for that kind of thing ? You could try something like: > > # perf probe --add mv_u3d_phy_write addr data > # perf probe --add mv_u3d_phy_read addr data > # perf record -gaR sleep 10 # it will record for 10 seconds > # perf report > > I didn't test that, but I think it could work and it wouldn't cause > a lot of overhead in your driver. > thanks, I can a try. Here I can remove this print. >> + pr_debug("%s: start calibration", __func__); > > drop all pr_* and convert them in to dev_* you have your dev pointer > saved on your mv_u3d_phy structure. > OK, I will. > -- > balbi -- 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