From 7777cb8ba08dabcab8dc0e91ac0a26dde675edb6 Mon Sep 17 00:00:00 2001 From: Simon Horman Date: Mon, 7 Mar 2016 10:58:40 +0900 Subject: phy: rcar-gen2: add fallback binding In the case of Renesas R-Car hardware we know that there are generations of SoCs, e.g. Gen 2 and Gen 3. But beyond that its not clear what the relationship between IP blocks might be. For example, I believe that r8a7790 is older than r8a7791 but that doesn't imply that the latter is a descendant of the former or vice versa. We can, however, by examining the documentation and behaviour of the hardware at run-time observe that the current driver implementation appears to be compatible with the IP blocks on SoCs within a given generation. For the above reasons and convenience when enabling new SoCs a per-generation fallback compatibility string scheme being adopted for drivers for Renesas SoCs. Signed-off-by: Simon Horman Acked-by: Geert Uytterhoeven Acked-by: Rob Herring Signed-off-by: Kishon Vijay Abraham I --- Documentation/devicetree/bindings/phy/rcar-gen2-phy.txt | 8 +++++++- drivers/phy/phy-rcar-gen2.c | 1 + 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/phy/rcar-gen2-phy.txt b/Documentation/devicetree/bindings/phy/rcar-gen2-phy.txt index d564ba4f1cf6..91da947ae9b6 100644 --- a/Documentation/devicetree/bindings/phy/rcar-gen2-phy.txt +++ b/Documentation/devicetree/bindings/phy/rcar-gen2-phy.txt @@ -7,6 +7,12 @@ Required properties: - compatible: "renesas,usb-phy-r8a7790" if the device is a part of R8A7790 SoC. "renesas,usb-phy-r8a7791" if the device is a part of R8A7791 SoC. "renesas,usb-phy-r8a7794" if the device is a part of R8A7794 SoC. + "renesas,rcar-gen2-usb-phy" for a generic R-Car Gen2 compatible device. + + When compatible with the generic version, nodes must list the + SoC-specific version corresponding to the platform first + followed by the generic version. + - reg: offset and length of the register block. - #address-cells: number of address cells for the USB channel subnodes, must be <1>. @@ -34,7 +40,7 @@ the USB channel; see the selector meanings below: Example (Lager board): usb-phy@e6590100 { - compatible = "renesas,usb-phy-r8a7790"; + compatible = "renesas,usb-phy-r8a7790", "renesas,rcar-gen2-usb-phy"; reg = <0 0xe6590100 0 0x100>; #address-cells = <1>; #size-cells = <0>; diff --git a/drivers/phy/phy-rcar-gen2.c b/drivers/phy/phy-rcar-gen2.c index c7a05996d5c1..97d4dd6ea924 100644 --- a/drivers/phy/phy-rcar-gen2.c +++ b/drivers/phy/phy-rcar-gen2.c @@ -195,6 +195,7 @@ static const struct of_device_id rcar_gen2_phy_match_table[] = { { .compatible = "renesas,usb-phy-r8a7790" }, { .compatible = "renesas,usb-phy-r8a7791" }, { .compatible = "renesas,usb-phy-r8a7794" }, + { .compatible = "renesas,rcar-gen2-usb-phy" }, { } }; MODULE_DEVICE_TABLE(of, rcar_gen2_phy_match_table); -- cgit v1.2.3 From cde7bc367f09e97deef143ebab3271153d87df00 Mon Sep 17 00:00:00 2001 From: Simon Horman Date: Mon, 7 Mar 2016 10:58:41 +0900 Subject: phy: rcar-gen3-usb2: add fallback binding In the case of Renesas R-Car hardware we know that there are generations of SoCs, e.g. Gen 2 and Gen 3. But beyond that its not clear what the relationship between IP blocks might be. For example, I believe that r8a7790 is older than r8a7791 but that doesn't imply that the latter is a descendant of the former or vice versa. We can, however, by examining the documentation and behaviour of the hardware at run-time observe that the current driver implementation appears to be compatible with the IP blocks on SoCs within a given generation. For the above reasons and convenience when enabling new SoCs a per-generation fallback compatibility string scheme being adopted for drivers for Renesas SoCs. Signed-off-by: Simon Horman Acked-by: Geert Uytterhoeven Acked-by: Rob Herring Acked-by: Yoshihiro Shimoda Signed-off-by: Kishon Vijay Abraham I --- Documentation/devicetree/bindings/phy/rcar-gen3-phy-usb2.txt | 10 ++++++++-- drivers/phy/phy-rcar-gen3-usb2.c | 1 + 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/Documentation/devicetree/bindings/phy/rcar-gen3-phy-usb2.txt b/Documentation/devicetree/bindings/phy/rcar-gen3-phy-usb2.txt index eaf7e9b7ce6b..f9511ad95b94 100644 --- a/Documentation/devicetree/bindings/phy/rcar-gen3-phy-usb2.txt +++ b/Documentation/devicetree/bindings/phy/rcar-gen3-phy-usb2.txt @@ -6,6 +6,12 @@ This file provides information on what the device node for the R-Car generation Required properties: - compatible: "renesas,usb2-phy-r8a7795" if the device is a part of an R8A7795 SoC. + "renesas,rcar-gen3-usb2-phy" for a generic R-Car Gen3 compatible device. + + When compatible with the generic version, nodes must list the + SoC-specific version corresponding to the platform first + followed by the generic version. + - reg: offset and length of the partial USB 2.0 Host register block. - clocks: clock phandle and specifier pair(s). - #phy-cells: see phy-bindings.txt in the same directory, must be <0>. @@ -19,14 +25,14 @@ channel as USB OTG: Example (R-Car H3): usb-phy@ee080200 { - compatible = "renesas,usb2-phy-r8a7795"; + compatible = "renesas,usb2-phy-r8a7795", "renesas,rcar-gen3-usb2-phy"; reg = <0 0xee080200 0 0x700>; interrupts = ; clocks = <&mstp7_clks R8A7795_CLK_EHCI0>; }; usb-phy@ee0a0200 { - compatible = "renesas,usb2-phy-r8a7795"; + compatible = "renesas,usb2-phy-r8a7795", "renesas,rcar-gen3-usb2-phy"; reg = <0 0xee0a0200 0 0x700>; clocks = <&mstp7_clks R8A7795_CLK_EHCI0>; }; diff --git a/drivers/phy/phy-rcar-gen3-usb2.c b/drivers/phy/phy-rcar-gen3-usb2.c index bc4f7dd821aa..257be74f93f5 100644 --- a/drivers/phy/phy-rcar-gen3-usb2.c +++ b/drivers/phy/phy-rcar-gen3-usb2.c @@ -251,6 +251,7 @@ static irqreturn_t rcar_gen3_phy_usb2_irq(int irq, void *_ch) static const struct of_device_id rcar_gen3_phy_usb2_match_table[] = { { .compatible = "renesas,usb2-phy-r8a7795" }, + { .compatible = "renesas,rcar-gen3-usb2-phy" }, { } }; MODULE_DEVICE_TABLE(of, rcar_gen3_phy_usb2_match_table); -- cgit v1.2.3 From ec9e80527621f8944aefbe870958c168bf47d09d Mon Sep 17 00:00:00 2001 From: Simon Horman Date: Mon, 7 Mar 2016 10:14:24 +0900 Subject: phy: rcar-gen3-usb2, rcar-gen2: Use ARCH_RENESAS Make use of ARCH_RENESAS in place of ARCH_SHMOBILE. A now redundant dependency on OF is also dropped. This is part of an ongoing process to migrate from ARCH_SHMOBILE to ARCH_RENESAS the motivation for which being that RENESAS seems to be a more appropriate name than SHMOBILE for the majority of Renesas ARM based SoCs. Signed-off-by: Simon Horman Acked-by: Yoshihiro Shimoda Acked-by: Geert Uytterhoeven Signed-off-by: Kishon Vijay Abraham I --- drivers/phy/Kconfig | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/phy/Kconfig b/drivers/phy/Kconfig index 26566db09de0..08f790a0af00 100644 --- a/drivers/phy/Kconfig +++ b/drivers/phy/Kconfig @@ -113,14 +113,14 @@ config PHY_MIPHY365X config PHY_RCAR_GEN2 tristate "Renesas R-Car generation 2 USB PHY driver" - depends on ARCH_SHMOBILE + depends on ARCH_RENESAS depends on GENERIC_PHY help Support for USB PHY found on Renesas R-Car generation 2 SoCs. config PHY_RCAR_GEN3_USB2 tristate "Renesas R-Car generation 3 USB 2.0 PHY driver" - depends on OF && ARCH_SHMOBILE + depends on ARCH_RENESAS select GENERIC_PHY help Support for USB 2.0 PHY found on Renesas R-Car generation 3 SoCs. -- cgit v1.2.3 From 037c418945edb9eb2006abe273910212af85629e Mon Sep 17 00:00:00 2001 From: Anup Patel Date: Mon, 28 Mar 2016 10:18:26 +0530 Subject: phy: Rename phy-brcmstb-sata driver to phy-brcm-sata driver Currently, we have a common SATA3 PHY driver for all Broadcom STB SoCs. This driver can be extended and re-used for Broadcom iProc SoCs having same SATA3 PHY. This patch renames existing Broadcom STB SATA3 PHY driver to common Broadcom SATA3 PHY driver to share this PHY driver across Broadcom SoCs. Signed-off-by: Anup Patel Acked-by: Florian Fainelli Signed-off-by: Kishon Vijay Abraham I --- drivers/phy/Kconfig | 18 +-- drivers/phy/Makefile | 2 +- drivers/phy/phy-brcm-sata.c | 250 +++++++++++++++++++++++++++++++++++++++++ drivers/phy/phy-brcmstb-sata.c | 250 ----------------------------------------- 4 files changed, 260 insertions(+), 260 deletions(-) create mode 100644 drivers/phy/phy-brcm-sata.c delete mode 100644 drivers/phy/phy-brcmstb-sata.c diff --git a/drivers/phy/Kconfig b/drivers/phy/Kconfig index 08f790a0af00..46bb2c2075d8 100644 --- a/drivers/phy/Kconfig +++ b/drivers/phy/Kconfig @@ -403,15 +403,6 @@ config PHY_TUSB1210 help Support for TI TUSB1210 USB ULPI PHY. -config PHY_BRCMSTB_SATA - tristate "Broadcom STB SATA PHY driver" - depends on ARCH_BRCMSTB || BMIPS_GENERIC - depends on OF - select GENERIC_PHY - help - Enable this to support the SATA3 PHY on 28nm or 40nm Broadcom STB SoCs. - Likely useful only with CONFIG_SATA_BRCMSTB enabled. - config PHY_CYGNUS_PCIE tristate "Broadcom Cygnus PCIe PHY driver" depends on OF && (ARCH_BCM_CYGNUS || COMPILE_TEST) @@ -421,4 +412,13 @@ config PHY_CYGNUS_PCIE Enable this to support the Broadcom Cygnus PCIe PHY. If unsure, say N. +config PHY_BRCM_SATA + tristate "Broadcom SATA PHY driver" + depends on ARCH_BRCMSTB || ARCH_BCM_IPROC || BMIPS_GENERIC || COMPILE_TEST + depends on OF + select GENERIC_PHY + default ARCH_BCM_IPROC + help + Enable this to support the Broadcom SATA PHY. + If unsure, say N. endmenu diff --git a/drivers/phy/Makefile b/drivers/phy/Makefile index 24596a96a887..596fae9b95d0 100644 --- a/drivers/phy/Makefile +++ b/drivers/phy/Makefile @@ -49,6 +49,6 @@ obj-$(CONFIG_PHY_QCOM_UFS) += phy-qcom-ufs.o obj-$(CONFIG_PHY_QCOM_UFS) += phy-qcom-ufs-qmp-20nm.o obj-$(CONFIG_PHY_QCOM_UFS) += phy-qcom-ufs-qmp-14nm.o obj-$(CONFIG_PHY_TUSB1210) += phy-tusb1210.o -obj-$(CONFIG_PHY_BRCMSTB_SATA) += phy-brcmstb-sata.o obj-$(CONFIG_PHY_PISTACHIO_USB) += phy-pistachio-usb.o obj-$(CONFIG_PHY_CYGNUS_PCIE) += phy-bcm-cygnus-pcie.o +obj-$(CONFIG_PHY_BRCM_SATA) += phy-brcm-sata.o diff --git a/drivers/phy/phy-brcm-sata.c b/drivers/phy/phy-brcm-sata.c new file mode 100644 index 000000000000..c97b9d6ff3e8 --- /dev/null +++ b/drivers/phy/phy-brcm-sata.c @@ -0,0 +1,250 @@ +/* + * Broadcom SATA3 AHCI Controller PHY Driver + * + * Copyright (C) 2016 Broadcom + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define SATA_MDIO_BANK_OFFSET 0x23c +#define SATA_MDIO_REG_OFFSET(ofs) ((ofs) * 4) + +#define MAX_PORTS 2 + +/* Register offset between PHYs in PCB space */ +#define SATA_MDIO_REG_28NM_SPACE_SIZE 0x1000 + +/* The older SATA PHY registers duplicated per port registers within the map, + * rather than having a separate map per port. + */ +#define SATA_MDIO_REG_40NM_SPACE_SIZE 0x10 + +enum brcm_sata_phy_version { + BRCM_SATA_PHY_28NM, + BRCM_SATA_PHY_40NM, +}; + +struct brcm_sata_port { + int portnum; + struct phy *phy; + struct brcm_sata_phy *phy_priv; + bool ssc_en; +}; + +struct brcm_sata_phy { + struct device *dev; + void __iomem *phy_base; + enum brcm_sata_phy_version version; + + struct brcm_sata_port phys[MAX_PORTS]; +}; + +enum sata_mdio_phy_regs { + PLL_REG_BANK_0 = 0x50, + PLL_REG_BANK_0_PLLCONTROL_0 = 0x81, + + TXPMD_REG_BANK = 0x1a0, + TXPMD_CONTROL1 = 0x81, + TXPMD_CONTROL1_TX_SSC_EN_FRC = BIT(0), + TXPMD_CONTROL1_TX_SSC_EN_FRC_VAL = BIT(1), + TXPMD_TX_FREQ_CTRL_CONTROL1 = 0x82, + TXPMD_TX_FREQ_CTRL_CONTROL2 = 0x83, + TXPMD_TX_FREQ_CTRL_CONTROL2_FMIN_MASK = 0x3ff, + TXPMD_TX_FREQ_CTRL_CONTROL3 = 0x84, + TXPMD_TX_FREQ_CTRL_CONTROL3_FMAX_MASK = 0x3ff, +}; + +static inline void __iomem *brcm_sata_phy_base(struct brcm_sata_port *port) +{ + struct brcm_sata_phy *priv = port->phy_priv; + u32 offset = 0; + + if (priv->version == BRCM_SATA_PHY_28NM) + offset = SATA_MDIO_REG_28NM_SPACE_SIZE; + else if (priv->version == BRCM_SATA_PHY_40NM) + offset = SATA_MDIO_REG_40NM_SPACE_SIZE; + else + dev_err(priv->dev, "invalid phy version\n"); + + return priv->phy_base + (port->portnum * offset); +} + +static void brcm_sata_mdio_wr(void __iomem *addr, u32 bank, u32 ofs, + u32 msk, u32 value) +{ + u32 tmp; + + writel(bank, addr + SATA_MDIO_BANK_OFFSET); + tmp = readl(addr + SATA_MDIO_REG_OFFSET(ofs)); + tmp = (tmp & msk) | value; + writel(tmp, addr + SATA_MDIO_REG_OFFSET(ofs)); +} + +/* These defaults were characterized by H/W group */ +#define FMIN_VAL_DEFAULT 0x3df +#define FMAX_VAL_DEFAULT 0x3df +#define FMAX_VAL_SSC 0x83 + +static void brcm_sata_cfg_ssc(struct brcm_sata_port *port) +{ + void __iomem *base = brcm_sata_phy_base(port); + struct brcm_sata_phy *priv = port->phy_priv; + u32 tmp; + + /* override the TX spread spectrum setting */ + tmp = TXPMD_CONTROL1_TX_SSC_EN_FRC_VAL | TXPMD_CONTROL1_TX_SSC_EN_FRC; + brcm_sata_mdio_wr(base, TXPMD_REG_BANK, TXPMD_CONTROL1, ~tmp, tmp); + + /* set fixed min freq */ + brcm_sata_mdio_wr(base, TXPMD_REG_BANK, TXPMD_TX_FREQ_CTRL_CONTROL2, + ~TXPMD_TX_FREQ_CTRL_CONTROL2_FMIN_MASK, + FMIN_VAL_DEFAULT); + + /* set fixed max freq depending on SSC config */ + if (port->ssc_en) { + dev_info(priv->dev, "enabling SSC on port %d\n", port->portnum); + tmp = FMAX_VAL_SSC; + } else { + tmp = FMAX_VAL_DEFAULT; + } + + brcm_sata_mdio_wr(base, TXPMD_REG_BANK, TXPMD_TX_FREQ_CTRL_CONTROL3, + ~TXPMD_TX_FREQ_CTRL_CONTROL3_FMAX_MASK, tmp); +} + +static int brcm_sata_phy_init(struct phy *phy) +{ + struct brcm_sata_port *port = phy_get_drvdata(phy); + + brcm_sata_cfg_ssc(port); + + return 0; +} + +static const struct phy_ops phy_ops = { + .init = brcm_sata_phy_init, + .owner = THIS_MODULE, +}; + +static const struct of_device_id brcm_sata_phy_of_match[] = { + { .compatible = "brcm,bcm7445-sata-phy", + .data = (void *)BRCM_SATA_PHY_28NM }, + { .compatible = "brcm,bcm7425-sata-phy", + .data = (void *)BRCM_SATA_PHY_40NM }, + {}, +}; +MODULE_DEVICE_TABLE(of, brcm_sata_phy_of_match); + +static int brcm_sata_phy_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct device_node *dn = dev->of_node, *child; + const struct of_device_id *of_id; + struct brcm_sata_phy *priv; + struct resource *res; + struct phy_provider *provider; + int ret, count = 0; + + if (of_get_child_count(dn) == 0) + return -ENODEV; + + priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + dev_set_drvdata(dev, priv); + priv->dev = dev; + + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "phy"); + priv->phy_base = devm_ioremap_resource(dev, res); + if (IS_ERR(priv->phy_base)) + return PTR_ERR(priv->phy_base); + + of_id = of_match_node(brcm_sata_phy_of_match, dn); + if (of_id) + priv->version = (enum brcm_sata_phy_version)of_id->data; + else + priv->version = BRCM_SATA_PHY_28NM; + + for_each_available_child_of_node(dn, child) { + unsigned int id; + struct brcm_sata_port *port; + + if (of_property_read_u32(child, "reg", &id)) { + dev_err(dev, "missing reg property in node %s\n", + child->name); + ret = -EINVAL; + goto put_child; + } + + if (id >= MAX_PORTS) { + dev_err(dev, "invalid reg: %u\n", id); + ret = -EINVAL; + goto put_child; + } + if (priv->phys[id].phy) { + dev_err(dev, "already registered port %u\n", id); + ret = -EINVAL; + goto put_child; + } + + port = &priv->phys[id]; + port->portnum = id; + port->phy_priv = priv; + port->phy = devm_phy_create(dev, child, &phy_ops); + port->ssc_en = of_property_read_bool(child, "brcm,enable-ssc"); + if (IS_ERR(port->phy)) { + dev_err(dev, "failed to create PHY\n"); + ret = PTR_ERR(port->phy); + goto put_child; + } + + phy_set_drvdata(port->phy, port); + count++; + } + + provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate); + if (IS_ERR(provider)) { + dev_err(dev, "could not register PHY provider\n"); + return PTR_ERR(provider); + } + + dev_info(dev, "registered %d port(s)\n", count); + + return 0; +put_child: + of_node_put(child); + return ret; +} + +static struct platform_driver brcm_sata_phy_driver = { + .probe = brcm_sata_phy_probe, + .driver = { + .of_match_table = brcm_sata_phy_of_match, + .name = "brcm-sata-phy", + } +}; +module_platform_driver(brcm_sata_phy_driver); + +MODULE_DESCRIPTION("Broadcom SATA PHY driver"); +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Marc Carino"); +MODULE_AUTHOR("Brian Norris"); +MODULE_ALIAS("platform:phy-brcm-sata"); diff --git a/drivers/phy/phy-brcmstb-sata.c b/drivers/phy/phy-brcmstb-sata.c deleted file mode 100644 index a23172ff40e3..000000000000 --- a/drivers/phy/phy-brcmstb-sata.c +++ /dev/null @@ -1,250 +0,0 @@ -/* - * Broadcom SATA3 AHCI Controller PHY Driver - * - * Copyright © 2009-2015 Broadcom Corporation - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define SATA_MDIO_BANK_OFFSET 0x23c -#define SATA_MDIO_REG_OFFSET(ofs) ((ofs) * 4) - -#define MAX_PORTS 2 - -/* Register offset between PHYs in PCB space */ -#define SATA_MDIO_REG_28NM_SPACE_SIZE 0x1000 - -/* The older SATA PHY registers duplicated per port registers within the map, - * rather than having a separate map per port. - */ -#define SATA_MDIO_REG_40NM_SPACE_SIZE 0x10 - -enum brcm_sata_phy_version { - BRCM_SATA_PHY_28NM, - BRCM_SATA_PHY_40NM, -}; - -struct brcm_sata_port { - int portnum; - struct phy *phy; - struct brcm_sata_phy *phy_priv; - bool ssc_en; -}; - -struct brcm_sata_phy { - struct device *dev; - void __iomem *phy_base; - enum brcm_sata_phy_version version; - - struct brcm_sata_port phys[MAX_PORTS]; -}; - -enum sata_mdio_phy_regs { - PLL_REG_BANK_0 = 0x50, - PLL_REG_BANK_0_PLLCONTROL_0 = 0x81, - - TXPMD_REG_BANK = 0x1a0, - TXPMD_CONTROL1 = 0x81, - TXPMD_CONTROL1_TX_SSC_EN_FRC = BIT(0), - TXPMD_CONTROL1_TX_SSC_EN_FRC_VAL = BIT(1), - TXPMD_TX_FREQ_CTRL_CONTROL1 = 0x82, - TXPMD_TX_FREQ_CTRL_CONTROL2 = 0x83, - TXPMD_TX_FREQ_CTRL_CONTROL2_FMIN_MASK = 0x3ff, - TXPMD_TX_FREQ_CTRL_CONTROL3 = 0x84, - TXPMD_TX_FREQ_CTRL_CONTROL3_FMAX_MASK = 0x3ff, -}; - -static inline void __iomem *brcm_sata_phy_base(struct brcm_sata_port *port) -{ - struct brcm_sata_phy *priv = port->phy_priv; - u32 offset = 0; - - if (priv->version == BRCM_SATA_PHY_28NM) - offset = SATA_MDIO_REG_28NM_SPACE_SIZE; - else if (priv->version == BRCM_SATA_PHY_40NM) - offset = SATA_MDIO_REG_40NM_SPACE_SIZE; - else - dev_err(priv->dev, "invalid phy version\n"); - - return priv->phy_base + (port->portnum * offset); -} - -static void brcm_sata_mdio_wr(void __iomem *addr, u32 bank, u32 ofs, - u32 msk, u32 value) -{ - u32 tmp; - - writel(bank, addr + SATA_MDIO_BANK_OFFSET); - tmp = readl(addr + SATA_MDIO_REG_OFFSET(ofs)); - tmp = (tmp & msk) | value; - writel(tmp, addr + SATA_MDIO_REG_OFFSET(ofs)); -} - -/* These defaults were characterized by H/W group */ -#define FMIN_VAL_DEFAULT 0x3df -#define FMAX_VAL_DEFAULT 0x3df -#define FMAX_VAL_SSC 0x83 - -static void brcm_sata_cfg_ssc(struct brcm_sata_port *port) -{ - void __iomem *base = brcm_sata_phy_base(port); - struct brcm_sata_phy *priv = port->phy_priv; - u32 tmp; - - /* override the TX spread spectrum setting */ - tmp = TXPMD_CONTROL1_TX_SSC_EN_FRC_VAL | TXPMD_CONTROL1_TX_SSC_EN_FRC; - brcm_sata_mdio_wr(base, TXPMD_REG_BANK, TXPMD_CONTROL1, ~tmp, tmp); - - /* set fixed min freq */ - brcm_sata_mdio_wr(base, TXPMD_REG_BANK, TXPMD_TX_FREQ_CTRL_CONTROL2, - ~TXPMD_TX_FREQ_CTRL_CONTROL2_FMIN_MASK, - FMIN_VAL_DEFAULT); - - /* set fixed max freq depending on SSC config */ - if (port->ssc_en) { - dev_info(priv->dev, "enabling SSC on port %d\n", port->portnum); - tmp = FMAX_VAL_SSC; - } else { - tmp = FMAX_VAL_DEFAULT; - } - - brcm_sata_mdio_wr(base, TXPMD_REG_BANK, TXPMD_TX_FREQ_CTRL_CONTROL3, - ~TXPMD_TX_FREQ_CTRL_CONTROL3_FMAX_MASK, tmp); -} - -static int brcm_sata_phy_init(struct phy *phy) -{ - struct brcm_sata_port *port = phy_get_drvdata(phy); - - brcm_sata_cfg_ssc(port); - - return 0; -} - -static const struct phy_ops phy_ops = { - .init = brcm_sata_phy_init, - .owner = THIS_MODULE, -}; - -static const struct of_device_id brcm_sata_phy_of_match[] = { - { .compatible = "brcm,bcm7445-sata-phy", - .data = (void *)BRCM_SATA_PHY_28NM }, - { .compatible = "brcm,bcm7425-sata-phy", - .data = (void *)BRCM_SATA_PHY_40NM }, - {}, -}; -MODULE_DEVICE_TABLE(of, brcm_sata_phy_of_match); - -static int brcm_sata_phy_probe(struct platform_device *pdev) -{ - struct device *dev = &pdev->dev; - struct device_node *dn = dev->of_node, *child; - const struct of_device_id *of_id; - struct brcm_sata_phy *priv; - struct resource *res; - struct phy_provider *provider; - int ret, count = 0; - - if (of_get_child_count(dn) == 0) - return -ENODEV; - - priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); - if (!priv) - return -ENOMEM; - dev_set_drvdata(dev, priv); - priv->dev = dev; - - res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "phy"); - priv->phy_base = devm_ioremap_resource(dev, res); - if (IS_ERR(priv->phy_base)) - return PTR_ERR(priv->phy_base); - - of_id = of_match_node(brcm_sata_phy_of_match, dn); - if (of_id) - priv->version = (enum brcm_sata_phy_version)of_id->data; - else - priv->version = BRCM_SATA_PHY_28NM; - - for_each_available_child_of_node(dn, child) { - unsigned int id; - struct brcm_sata_port *port; - - if (of_property_read_u32(child, "reg", &id)) { - dev_err(dev, "missing reg property in node %s\n", - child->name); - ret = -EINVAL; - goto put_child; - } - - if (id >= MAX_PORTS) { - dev_err(dev, "invalid reg: %u\n", id); - ret = -EINVAL; - goto put_child; - } - if (priv->phys[id].phy) { - dev_err(dev, "already registered port %u\n", id); - ret = -EINVAL; - goto put_child; - } - - port = &priv->phys[id]; - port->portnum = id; - port->phy_priv = priv; - port->phy = devm_phy_create(dev, child, &phy_ops); - port->ssc_en = of_property_read_bool(child, "brcm,enable-ssc"); - if (IS_ERR(port->phy)) { - dev_err(dev, "failed to create PHY\n"); - ret = PTR_ERR(port->phy); - goto put_child; - } - - phy_set_drvdata(port->phy, port); - count++; - } - - provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate); - if (IS_ERR(provider)) { - dev_err(dev, "could not register PHY provider\n"); - return PTR_ERR(provider); - } - - dev_info(dev, "registered %d port(s)\n", count); - - return 0; -put_child: - of_node_put(child); - return ret; -} - -static struct platform_driver brcm_sata_phy_driver = { - .probe = brcm_sata_phy_probe, - .driver = { - .of_match_table = brcm_sata_phy_of_match, - .name = "brcmstb-sata-phy", - } -}; -module_platform_driver(brcm_sata_phy_driver); - -MODULE_DESCRIPTION("Broadcom STB SATA PHY driver"); -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Marc Carino"); -MODULE_AUTHOR("Brian Norris"); -MODULE_ALIAS("platform:phy-brcmstb-sata"); -- cgit v1.2.3 From 4faee9a43d0af2943195cdbde93c59d03984b749 Mon Sep 17 00:00:00 2001 From: Anup Patel Date: Mon, 28 Mar 2016 10:18:27 +0530 Subject: phy: Add support for NS2 SATA3 PHY in Broadcom SATA3 PHY driver This patch adds support for Broadcom NS2 SATA3 PHY in existing Broadcom SATA3 PHY driver. Signed-off-by: Anup Patel Acked-by: Florian Fainelli Signed-off-by: Kishon Vijay Abraham I --- drivers/phy/Kconfig | 19 ++-- drivers/phy/Makefile | 2 +- drivers/phy/phy-brcm-sata.c | 238 +++++++++++++++++++++++++++++++++++++------- 3 files changed, 211 insertions(+), 48 deletions(-) diff --git a/drivers/phy/Kconfig b/drivers/phy/Kconfig index 46bb2c2075d8..a72d73cdaef3 100644 --- a/drivers/phy/Kconfig +++ b/drivers/phy/Kconfig @@ -403,15 +403,6 @@ config PHY_TUSB1210 help Support for TI TUSB1210 USB ULPI PHY. -config PHY_CYGNUS_PCIE - tristate "Broadcom Cygnus PCIe PHY driver" - depends on OF && (ARCH_BCM_CYGNUS || COMPILE_TEST) - select GENERIC_PHY - default ARCH_BCM_CYGNUS - help - Enable this to support the Broadcom Cygnus PCIe PHY. - If unsure, say N. - config PHY_BRCM_SATA tristate "Broadcom SATA PHY driver" depends on ARCH_BRCMSTB || ARCH_BCM_IPROC || BMIPS_GENERIC || COMPILE_TEST @@ -421,4 +412,14 @@ config PHY_BRCM_SATA help Enable this to support the Broadcom SATA PHY. If unsure, say N. + +config PHY_CYGNUS_PCIE + tristate "Broadcom Cygnus PCIe PHY driver" + depends on OF && (ARCH_BCM_CYGNUS || COMPILE_TEST) + select GENERIC_PHY + default ARCH_BCM_CYGNUS + help + Enable this to support the Broadcom Cygnus PCIe PHY. + If unsure, say N. + endmenu diff --git a/drivers/phy/Makefile b/drivers/phy/Makefile index 596fae9b95d0..f03fa1fdf322 100644 --- a/drivers/phy/Makefile +++ b/drivers/phy/Makefile @@ -49,6 +49,6 @@ obj-$(CONFIG_PHY_QCOM_UFS) += phy-qcom-ufs.o obj-$(CONFIG_PHY_QCOM_UFS) += phy-qcom-ufs-qmp-20nm.o obj-$(CONFIG_PHY_QCOM_UFS) += phy-qcom-ufs-qmp-14nm.o obj-$(CONFIG_PHY_TUSB1210) += phy-tusb1210.o +obj-$(CONFIG_PHY_BRCM_SATA) += phy-brcm-sata.o obj-$(CONFIG_PHY_PISTACHIO_USB) += phy-pistachio-usb.o obj-$(CONFIG_PHY_CYGNUS_PCIE) += phy-bcm-cygnus-pcie.o -obj-$(CONFIG_PHY_BRCM_SATA) += phy-brcm-sata.o diff --git a/drivers/phy/phy-brcm-sata.c b/drivers/phy/phy-brcm-sata.c index c97b9d6ff3e8..6c4c5cb791ca 100644 --- a/drivers/phy/phy-brcm-sata.c +++ b/drivers/phy/phy-brcm-sata.c @@ -14,6 +14,7 @@ * GNU General Public License for more details. */ +#include #include #include #include @@ -24,22 +25,26 @@ #include #include -#define SATA_MDIO_BANK_OFFSET 0x23c -#define SATA_MDIO_REG_OFFSET(ofs) ((ofs) * 4) +#define SATA_PCB_BANK_OFFSET 0x23c +#define SATA_PCB_REG_OFFSET(ofs) ((ofs) * 4) #define MAX_PORTS 2 /* Register offset between PHYs in PCB space */ -#define SATA_MDIO_REG_28NM_SPACE_SIZE 0x1000 +#define SATA_PCB_REG_28NM_SPACE_SIZE 0x1000 /* The older SATA PHY registers duplicated per port registers within the map, * rather than having a separate map per port. */ -#define SATA_MDIO_REG_40NM_SPACE_SIZE 0x10 +#define SATA_PCB_REG_40NM_SPACE_SIZE 0x10 + +/* Register offset between PHYs in PHY control space */ +#define SATA_PHY_CTRL_REG_28NM_SPACE_SIZE 0x8 enum brcm_sata_phy_version { - BRCM_SATA_PHY_28NM, - BRCM_SATA_PHY_40NM, + BRCM_SATA_PHY_STB_28NM, + BRCM_SATA_PHY_STB_40NM, + BRCM_SATA_PHY_IPROC_NS2, }; struct brcm_sata_port { @@ -52,15 +57,48 @@ struct brcm_sata_port { struct brcm_sata_phy { struct device *dev; void __iomem *phy_base; + void __iomem *ctrl_base; enum brcm_sata_phy_version version; struct brcm_sata_port phys[MAX_PORTS]; }; -enum sata_mdio_phy_regs { - PLL_REG_BANK_0 = 0x50, +enum sata_phy_regs { + BLOCK0_REG_BANK = 0x000, + BLOCK0_XGXSSTATUS = 0x81, + BLOCK0_XGXSSTATUS_PLL_LOCK = BIT(12), + BLOCK0_SPARE = 0x8d, + BLOCK0_SPARE_OOB_CLK_SEL_MASK = 0x3, + BLOCK0_SPARE_OOB_CLK_SEL_REFBY2 = 0x1, + + PLL_REG_BANK_0 = 0x050, PLL_REG_BANK_0_PLLCONTROL_0 = 0x81, + PLL1_REG_BANK = 0x060, + PLL1_ACTRL2 = 0x82, + PLL1_ACTRL3 = 0x83, + PLL1_ACTRL4 = 0x84, + + OOB_REG_BANK = 0x150, + OOB_CTRL1 = 0x80, + OOB_CTRL1_BURST_MAX_MASK = 0xf, + OOB_CTRL1_BURST_MAX_SHIFT = 12, + OOB_CTRL1_BURST_MIN_MASK = 0xf, + OOB_CTRL1_BURST_MIN_SHIFT = 8, + OOB_CTRL1_WAKE_IDLE_MAX_MASK = 0xf, + OOB_CTRL1_WAKE_IDLE_MAX_SHIFT = 4, + OOB_CTRL1_WAKE_IDLE_MIN_MASK = 0xf, + OOB_CTRL1_WAKE_IDLE_MIN_SHIFT = 0, + OOB_CTRL2 = 0x81, + OOB_CTRL2_SEL_ENA_SHIFT = 15, + OOB_CTRL2_SEL_ENA_RC_SHIFT = 14, + OOB_CTRL2_RESET_IDLE_MAX_MASK = 0x3f, + OOB_CTRL2_RESET_IDLE_MAX_SHIFT = 8, + OOB_CTRL2_BURST_CNT_MASK = 0x3, + OOB_CTRL2_BURST_CNT_SHIFT = 6, + OOB_CTRL2_RESET_IDLE_MIN_MASK = 0x3f, + OOB_CTRL2_RESET_IDLE_MIN_SHIFT = 0, + TXPMD_REG_BANK = 0x1a0, TXPMD_CONTROL1 = 0x81, TXPMD_CONTROL1_TX_SSC_EN_FRC = BIT(0), @@ -72,69 +110,183 @@ enum sata_mdio_phy_regs { TXPMD_TX_FREQ_CTRL_CONTROL3_FMAX_MASK = 0x3ff, }; -static inline void __iomem *brcm_sata_phy_base(struct brcm_sata_port *port) +enum sata_phy_ctrl_regs { + PHY_CTRL_1 = 0x0, + PHY_CTRL_1_RESET = BIT(0), +}; + +static inline void __iomem *brcm_sata_pcb_base(struct brcm_sata_port *port) { struct brcm_sata_phy *priv = port->phy_priv; - u32 offset = 0; + u32 size = 0; + + switch (priv->version) { + case BRCM_SATA_PHY_STB_28NM: + case BRCM_SATA_PHY_IPROC_NS2: + size = SATA_PCB_REG_28NM_SPACE_SIZE; + break; + case BRCM_SATA_PHY_STB_40NM: + size = SATA_PCB_REG_40NM_SPACE_SIZE; + break; + default: + dev_err(priv->dev, "invalid phy version\n"); + break; + }; - if (priv->version == BRCM_SATA_PHY_28NM) - offset = SATA_MDIO_REG_28NM_SPACE_SIZE; - else if (priv->version == BRCM_SATA_PHY_40NM) - offset = SATA_MDIO_REG_40NM_SPACE_SIZE; - else + return priv->phy_base + (port->portnum * size); +} + +static inline void __iomem *brcm_sata_ctrl_base(struct brcm_sata_port *port) +{ + struct brcm_sata_phy *priv = port->phy_priv; + u32 size = 0; + + switch (priv->version) { + case BRCM_SATA_PHY_IPROC_NS2: + size = SATA_PHY_CTRL_REG_28NM_SPACE_SIZE; + break; + default: dev_err(priv->dev, "invalid phy version\n"); + break; + }; - return priv->phy_base + (port->portnum * offset); + return priv->ctrl_base + (port->portnum * size); } -static void brcm_sata_mdio_wr(void __iomem *addr, u32 bank, u32 ofs, - u32 msk, u32 value) +static void brcm_sata_phy_wr(void __iomem *pcb_base, u32 bank, + u32 ofs, u32 msk, u32 value) { u32 tmp; - writel(bank, addr + SATA_MDIO_BANK_OFFSET); - tmp = readl(addr + SATA_MDIO_REG_OFFSET(ofs)); + writel(bank, pcb_base + SATA_PCB_BANK_OFFSET); + tmp = readl(pcb_base + SATA_PCB_REG_OFFSET(ofs)); tmp = (tmp & msk) | value; - writel(tmp, addr + SATA_MDIO_REG_OFFSET(ofs)); + writel(tmp, pcb_base + SATA_PCB_REG_OFFSET(ofs)); +} + +static u32 brcm_sata_phy_rd(void __iomem *pcb_base, u32 bank, u32 ofs) +{ + writel(bank, pcb_base + SATA_PCB_BANK_OFFSET); + return readl(pcb_base + SATA_PCB_REG_OFFSET(ofs)); } /* These defaults were characterized by H/W group */ -#define FMIN_VAL_DEFAULT 0x3df -#define FMAX_VAL_DEFAULT 0x3df -#define FMAX_VAL_SSC 0x83 +#define STB_FMIN_VAL_DEFAULT 0x3df +#define STB_FMAX_VAL_DEFAULT 0x3df +#define STB_FMAX_VAL_SSC 0x83 -static void brcm_sata_cfg_ssc(struct brcm_sata_port *port) +static int brcm_stb_sata_init(struct brcm_sata_port *port) { - void __iomem *base = brcm_sata_phy_base(port); + void __iomem *base = brcm_sata_pcb_base(port); struct brcm_sata_phy *priv = port->phy_priv; u32 tmp; /* override the TX spread spectrum setting */ tmp = TXPMD_CONTROL1_TX_SSC_EN_FRC_VAL | TXPMD_CONTROL1_TX_SSC_EN_FRC; - brcm_sata_mdio_wr(base, TXPMD_REG_BANK, TXPMD_CONTROL1, ~tmp, tmp); + brcm_sata_phy_wr(base, TXPMD_REG_BANK, TXPMD_CONTROL1, ~tmp, tmp); /* set fixed min freq */ - brcm_sata_mdio_wr(base, TXPMD_REG_BANK, TXPMD_TX_FREQ_CTRL_CONTROL2, - ~TXPMD_TX_FREQ_CTRL_CONTROL2_FMIN_MASK, - FMIN_VAL_DEFAULT); + brcm_sata_phy_wr(base, TXPMD_REG_BANK, TXPMD_TX_FREQ_CTRL_CONTROL2, + ~TXPMD_TX_FREQ_CTRL_CONTROL2_FMIN_MASK, + STB_FMIN_VAL_DEFAULT); /* set fixed max freq depending on SSC config */ if (port->ssc_en) { - dev_info(priv->dev, "enabling SSC on port %d\n", port->portnum); - tmp = FMAX_VAL_SSC; + dev_info(priv->dev, "enabling SSC on port%d\n", port->portnum); + tmp = STB_FMAX_VAL_SSC; } else { - tmp = FMAX_VAL_DEFAULT; + tmp = STB_FMAX_VAL_DEFAULT; } - brcm_sata_mdio_wr(base, TXPMD_REG_BANK, TXPMD_TX_FREQ_CTRL_CONTROL3, + brcm_sata_phy_wr(base, TXPMD_REG_BANK, TXPMD_TX_FREQ_CTRL_CONTROL3, ~TXPMD_TX_FREQ_CTRL_CONTROL3_FMAX_MASK, tmp); + + return 0; +} + +/* NS2 SATA PLL1 defaults were characterized by H/W group */ +#define NS2_PLL1_ACTRL2_MAGIC 0x1df8 +#define NS2_PLL1_ACTRL3_MAGIC 0x2b00 +#define NS2_PLL1_ACTRL4_MAGIC 0x8824 + +static int brcm_ns2_sata_init(struct brcm_sata_port *port) +{ + int try; + unsigned int val; + void __iomem *base = brcm_sata_pcb_base(port); + void __iomem *ctrl_base = brcm_sata_ctrl_base(port); + struct device *dev = port->phy_priv->dev; + + /* Configure OOB control */ + val = 0x0; + val |= (0xc << OOB_CTRL1_BURST_MAX_SHIFT); + val |= (0x4 << OOB_CTRL1_BURST_MIN_SHIFT); + val |= (0x9 << OOB_CTRL1_WAKE_IDLE_MAX_SHIFT); + val |= (0x3 << OOB_CTRL1_WAKE_IDLE_MIN_SHIFT); + brcm_sata_phy_wr(base, OOB_REG_BANK, OOB_CTRL1, 0x0, val); + val = 0x0; + val |= (0x1b << OOB_CTRL2_RESET_IDLE_MAX_SHIFT); + val |= (0x2 << OOB_CTRL2_BURST_CNT_SHIFT); + val |= (0x9 << OOB_CTRL2_RESET_IDLE_MIN_SHIFT); + brcm_sata_phy_wr(base, OOB_REG_BANK, OOB_CTRL2, 0x0, val); + + /* Configure PHY PLL register bank 1 */ + val = NS2_PLL1_ACTRL2_MAGIC; + brcm_sata_phy_wr(base, PLL1_REG_BANK, PLL1_ACTRL2, 0x0, val); + val = NS2_PLL1_ACTRL3_MAGIC; + brcm_sata_phy_wr(base, PLL1_REG_BANK, PLL1_ACTRL3, 0x0, val); + val = NS2_PLL1_ACTRL4_MAGIC; + brcm_sata_phy_wr(base, PLL1_REG_BANK, PLL1_ACTRL4, 0x0, val); + + /* Configure PHY BLOCK0 register bank */ + /* Set oob_clk_sel to refclk/2 */ + brcm_sata_phy_wr(base, BLOCK0_REG_BANK, BLOCK0_SPARE, + ~BLOCK0_SPARE_OOB_CLK_SEL_MASK, + BLOCK0_SPARE_OOB_CLK_SEL_REFBY2); + + /* Strobe PHY reset using PHY control register */ + writel(PHY_CTRL_1_RESET, ctrl_base + PHY_CTRL_1); + mdelay(1); + writel(0x0, ctrl_base + PHY_CTRL_1); + mdelay(1); + + /* Wait for PHY PLL lock by polling pll_lock bit */ + try = 50; + while (try) { + val = brcm_sata_phy_rd(base, BLOCK0_REG_BANK, + BLOCK0_XGXSSTATUS); + if (val & BLOCK0_XGXSSTATUS_PLL_LOCK) + break; + msleep(20); + try--; + } + if (!try) { + /* PLL did not lock; give up */ + dev_err(dev, "port%d PLL did not lock\n", port->portnum); + return -ETIMEDOUT; + } + + dev_dbg(dev, "port%d initialized\n", port->portnum); + + return 0; } static int brcm_sata_phy_init(struct phy *phy) { + int rc; struct brcm_sata_port *port = phy_get_drvdata(phy); - brcm_sata_cfg_ssc(port); + switch (port->phy_priv->version) { + case BRCM_SATA_PHY_STB_28NM: + case BRCM_SATA_PHY_STB_40NM: + rc = brcm_stb_sata_init(port); + break; + case BRCM_SATA_PHY_IPROC_NS2: + rc = brcm_ns2_sata_init(port); + break; + default: + rc = -ENODEV; + }; return 0; } @@ -146,9 +298,11 @@ static const struct phy_ops phy_ops = { static const struct of_device_id brcm_sata_phy_of_match[] = { { .compatible = "brcm,bcm7445-sata-phy", - .data = (void *)BRCM_SATA_PHY_28NM }, + .data = (void *)BRCM_SATA_PHY_STB_28NM }, { .compatible = "brcm,bcm7425-sata-phy", - .data = (void *)BRCM_SATA_PHY_40NM }, + .data = (void *)BRCM_SATA_PHY_STB_40NM }, + { .compatible = "brcm,iproc-ns2-sata-phy", + .data = (void *)BRCM_SATA_PHY_IPROC_NS2 }, {}, }; MODULE_DEVICE_TABLE(of, brcm_sata_phy_of_match); @@ -181,7 +335,15 @@ static int brcm_sata_phy_probe(struct platform_device *pdev) if (of_id) priv->version = (enum brcm_sata_phy_version)of_id->data; else - priv->version = BRCM_SATA_PHY_28NM; + priv->version = BRCM_SATA_PHY_STB_28NM; + + if (priv->version == BRCM_SATA_PHY_IPROC_NS2) { + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, + "phy-ctrl"); + priv->ctrl_base = devm_ioremap_resource(dev, res); + if (IS_ERR(priv->ctrl_base)) + return PTR_ERR(priv->ctrl_base); + } for_each_available_child_of_node(dn, child) { unsigned int id; -- cgit v1.2.3 From 2bcdf18189632fb67d10d8e5b07fba36ad594227 Mon Sep 17 00:00:00 2001 From: Anup Patel Date: Mon, 28 Mar 2016 10:18:28 +0530 Subject: dt-bindings: phy: bindings document for common Broadcom SATA3 PHY driver This patch: 1. Renames DT bindings document of Broadcom STB SATA3 PHY driver to common Broadcom SATA3 PHY driver bindings document 2. Adds bindings info for NS2 SATA3 PHY Signed-off-by: Anup Patel Acked-by: Rob Herring Acked-by: Florian Fainelli Signed-off-by: Kishon Vijay Abraham I --- .../bindings/phy/brcm,brcmstb-sata-phy.txt | 41 -------------------- .../devicetree/bindings/phy/brcm-sata-phy.txt | 44 ++++++++++++++++++++++ 2 files changed, 44 insertions(+), 41 deletions(-) delete mode 100644 Documentation/devicetree/bindings/phy/brcm,brcmstb-sata-phy.txt create mode 100644 Documentation/devicetree/bindings/phy/brcm-sata-phy.txt diff --git a/Documentation/devicetree/bindings/phy/brcm,brcmstb-sata-phy.txt b/Documentation/devicetree/bindings/phy/brcm,brcmstb-sata-phy.txt deleted file mode 100644 index d87ab7c127b8..000000000000 --- a/Documentation/devicetree/bindings/phy/brcm,brcmstb-sata-phy.txt +++ /dev/null @@ -1,41 +0,0 @@ -* Broadcom SATA3 PHY for STB - -Required properties: -- compatible: should be one or more of - "brcm,bcm7425-sata-phy" - "brcm,bcm7445-sata-phy" - "brcm,phy-sata3" -- address-cells: should be 1 -- size-cells: should be 0 -- reg: register range for the PHY PCB interface -- reg-names: should be "phy" - -Sub-nodes: - Each port's PHY should be represented as a sub-node. - -Sub-nodes required properties: -- reg: the PHY number -- phy-cells: generic PHY binding; must be 0 -Optional: -- brcm,enable-ssc: use spread spectrum clocking (SSC) on this port - - -Example: - - sata-phy@f0458100 { - compatible = "brcm,bcm7445-sata-phy", "brcm,phy-sata3"; - reg = <0xf0458100 0x1e00>, <0xf045804c 0x10>; - reg-names = "phy"; - #address-cells = <1>; - #size-cells = <0>; - - sata-phy@0 { - reg = <0>; - #phy-cells = <0>; - }; - - sata-phy@1 { - reg = <1>; - #phy-cells = <0>; - }; - }; diff --git a/Documentation/devicetree/bindings/phy/brcm-sata-phy.txt b/Documentation/devicetree/bindings/phy/brcm-sata-phy.txt new file mode 100644 index 000000000000..d0231209d846 --- /dev/null +++ b/Documentation/devicetree/bindings/phy/brcm-sata-phy.txt @@ -0,0 +1,44 @@ +* Broadcom SATA3 PHY + +Required properties: +- compatible: should be one or more of + "brcm,bcm7425-sata-phy" + "brcm,bcm7445-sata-phy" + "brcm,iproc-ns2-sata-phy" + "brcm,phy-sata3" +- address-cells: should be 1 +- size-cells: should be 0 +- reg: register ranges for the PHY PCB interface +- reg-names: should be "phy" and "phy-ctrl" + The "phy-ctrl" registers are only required for + "brcm,iproc-ns2-sata-phy". + +Sub-nodes: + Each port's PHY should be represented as a sub-node. + +Sub-nodes required properties: +- reg: the PHY number +- phy-cells: generic PHY binding; must be 0 + +Sub-nodes optional properties: +- brcm,enable-ssc: use spread spectrum clocking (SSC) on this port + This property is not applicable for "brcm,iproc-ns2-sata-phy". + +Example: + sata-phy@f0458100 { + compatible = "brcm,bcm7445-sata-phy", "brcm,phy-sata3"; + reg = <0xf0458100 0x1e00>, <0xf045804c 0x10>; + reg-names = "phy"; + #address-cells = <1>; + #size-cells = <0>; + + sata-phy@0 { + reg = <0>; + #phy-cells = <0>; + }; + + sata-phy@1 { + reg = <1>; + #phy-cells = <0>; + }; + }; -- cgit v1.2.3 From 801a69c787812f987f38feb2f54782bcf2a4a007 Mon Sep 17 00:00:00 2001 From: Yoshihiro Shimoda Date: Thu, 3 Mar 2016 19:09:04 +0900 Subject: phy: rcar-gen3-usb2: remove unnecesary struct rcar_gen3_data Since this driver uses the struct rcar_gen3_data in struct rcar_gen3_chan only, we can remove the rcar_gen3_data. Signed-off-by: Yoshihiro Shimoda Signed-off-by: Kishon Vijay Abraham I --- drivers/phy/phy-rcar-gen3-usb2.c | 33 ++++++++++++++------------------- 1 file changed, 14 insertions(+), 19 deletions(-) diff --git a/drivers/phy/phy-rcar-gen3-usb2.c b/drivers/phy/phy-rcar-gen3-usb2.c index 257be74f93f5..3c647cd9c432 100644 --- a/drivers/phy/phy-rcar-gen3-usb2.c +++ b/drivers/phy/phy-rcar-gen3-usb2.c @@ -74,20 +74,15 @@ #define USB2_ADPCTRL_IDPULLUP BIT(5) /* 1 = ID sampling is enabled */ #define USB2_ADPCTRL_DRVVBUS BIT(4) -struct rcar_gen3_data { - void __iomem *base; - struct clk *clk; -}; - struct rcar_gen3_chan { - struct rcar_gen3_data usb2; + void __iomem *base; struct phy *phy; bool has_otg; }; static void rcar_gen3_set_host_mode(struct rcar_gen3_chan *ch, int host) { - void __iomem *usb2_base = ch->usb2.base; + void __iomem *usb2_base = ch->base; u32 val = readl(usb2_base + USB2_COMMCTRL); dev_vdbg(&ch->phy->dev, "%s: %08x, %d\n", __func__, val, host); @@ -100,7 +95,7 @@ static void rcar_gen3_set_host_mode(struct rcar_gen3_chan *ch, int host) static void rcar_gen3_set_linectrl(struct rcar_gen3_chan *ch, int dp, int dm) { - void __iomem *usb2_base = ch->usb2.base; + void __iomem *usb2_base = ch->base; u32 val = readl(usb2_base + USB2_LINECTRL1); dev_vdbg(&ch->phy->dev, "%s: %08x, %d, %d\n", __func__, val, dp, dm); @@ -114,7 +109,7 @@ static void rcar_gen3_set_linectrl(struct rcar_gen3_chan *ch, int dp, int dm) static void rcar_gen3_enable_vbus_ctrl(struct rcar_gen3_chan *ch, int vbus) { - void __iomem *usb2_base = ch->usb2.base; + void __iomem *usb2_base = ch->base; u32 val = readl(usb2_base + USB2_ADPCTRL); dev_vdbg(&ch->phy->dev, "%s: %08x, %d\n", __func__, val, vbus); @@ -141,13 +136,13 @@ static void rcar_gen3_init_for_peri(struct rcar_gen3_chan *ch) static bool rcar_gen3_check_vbus(struct rcar_gen3_chan *ch) { - return !!(readl(ch->usb2.base + USB2_ADPCTRL) & + return !!(readl(ch->base + USB2_ADPCTRL) & USB2_ADPCTRL_OTGSESSVLD); } static bool rcar_gen3_check_id(struct rcar_gen3_chan *ch) { - return !!(readl(ch->usb2.base + USB2_ADPCTRL) & USB2_ADPCTRL_IDDIG); + return !!(readl(ch->base + USB2_ADPCTRL) & USB2_ADPCTRL_IDDIG); } static void rcar_gen3_device_recognition(struct rcar_gen3_chan *ch) @@ -166,7 +161,7 @@ static void rcar_gen3_device_recognition(struct rcar_gen3_chan *ch) static void rcar_gen3_init_otg(struct rcar_gen3_chan *ch) { - void __iomem *usb2_base = ch->usb2.base; + void __iomem *usb2_base = ch->base; u32 val; val = readl(usb2_base + USB2_VBCTRL); @@ -187,7 +182,7 @@ static void rcar_gen3_init_otg(struct rcar_gen3_chan *ch) static int rcar_gen3_phy_usb2_init(struct phy *p) { struct rcar_gen3_chan *channel = phy_get_drvdata(p); - void __iomem *usb2_base = channel->usb2.base; + void __iomem *usb2_base = channel->base; /* Initialize USB2 part */ writel(USB2_INT_ENABLE_INIT, usb2_base + USB2_INT_ENABLE); @@ -205,7 +200,7 @@ static int rcar_gen3_phy_usb2_exit(struct phy *p) { struct rcar_gen3_chan *channel = phy_get_drvdata(p); - writel(0, channel->usb2.base + USB2_INT_ENABLE); + writel(0, channel->base + USB2_INT_ENABLE); return 0; } @@ -213,7 +208,7 @@ static int rcar_gen3_phy_usb2_exit(struct phy *p) static int rcar_gen3_phy_usb2_power_on(struct phy *p) { struct rcar_gen3_chan *channel = phy_get_drvdata(p); - void __iomem *usb2_base = channel->usb2.base; + void __iomem *usb2_base = channel->base; u32 val; val = readl(usb2_base + USB2_USBCTR); @@ -235,7 +230,7 @@ static struct phy_ops rcar_gen3_phy_usb2_ops = { static irqreturn_t rcar_gen3_phy_usb2_irq(int irq, void *_ch) { struct rcar_gen3_chan *ch = _ch; - void __iomem *usb2_base = ch->usb2.base; + void __iomem *usb2_base = ch->base; u32 status = readl(usb2_base + USB2_OBINTSTA); irqreturn_t ret = IRQ_NONE; @@ -274,9 +269,9 @@ static int rcar_gen3_phy_usb2_probe(struct platform_device *pdev) return -ENOMEM; res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - channel->usb2.base = devm_ioremap_resource(dev, res); - if (IS_ERR(channel->usb2.base)) - return PTR_ERR(channel->usb2.base); + channel->base = devm_ioremap_resource(dev, res); + if (IS_ERR(channel->base)) + return PTR_ERR(channel->base); /* call request_irq for OTG */ irq = platform_get_irq(pdev, 0); -- cgit v1.2.3 From 6dcfd7c300bf3588d4f2500e14d90ffea5595e84 Mon Sep 17 00:00:00 2001 From: Yoshihiro Shimoda Date: Thu, 3 Mar 2016 19:09:05 +0900 Subject: phy: rcar-gen3-usb2: Add vbus-supply to handle VBUS on/off To handle the VBUS on/off by a regulator driver, this patch adds regulator APIs calling in the driver and description about vbus-supply in the rcar-gen3-phy-usb2.txt. Signed-off-by: Yoshihiro Shimoda Acked-by: Rob Herring Signed-off-by: Kishon Vijay Abraham I --- .../devicetree/bindings/phy/rcar-gen3-phy-usb2.txt | 2 ++ drivers/phy/phy-rcar-gen3-usb2.c | 28 ++++++++++++++++++++++ 2 files changed, 30 insertions(+) diff --git a/Documentation/devicetree/bindings/phy/rcar-gen3-phy-usb2.txt b/Documentation/devicetree/bindings/phy/rcar-gen3-phy-usb2.txt index f9511ad95b94..2281d6cdecb1 100644 --- a/Documentation/devicetree/bindings/phy/rcar-gen3-phy-usb2.txt +++ b/Documentation/devicetree/bindings/phy/rcar-gen3-phy-usb2.txt @@ -21,6 +21,8 @@ To use a USB channel where USB 2.0 Host and HSUSB (USB 2.0 Peripheral) are combined, the device tree node should set interrupt properties to use the channel as USB OTG: - interrupts: interrupt specifier for the PHY. +- vbus-supply: Phandle to a regulator that provides power to the VBUS. This + regulator will be managed during the PHY power on/off sequence. Example (R-Car H3): diff --git a/drivers/phy/phy-rcar-gen3-usb2.c b/drivers/phy/phy-rcar-gen3-usb2.c index 3c647cd9c432..7b14244be285 100644 --- a/drivers/phy/phy-rcar-gen3-usb2.c +++ b/drivers/phy/phy-rcar-gen3-usb2.c @@ -19,6 +19,7 @@ #include #include #include +#include /******* USB2.0 Host registers (original offset is +0x200) *******/ #define USB2_INT_ENABLE 0x000 @@ -77,6 +78,7 @@ struct rcar_gen3_chan { void __iomem *base; struct phy *phy; + struct regulator *vbus; bool has_otg; }; @@ -210,6 +212,13 @@ static int rcar_gen3_phy_usb2_power_on(struct phy *p) struct rcar_gen3_chan *channel = phy_get_drvdata(p); void __iomem *usb2_base = channel->base; u32 val; + int ret; + + if (channel->vbus) { + ret = regulator_enable(channel->vbus); + if (ret) + return ret; + } val = readl(usb2_base + USB2_USBCTR); val |= USB2_USBCTR_PLL_RST; @@ -220,10 +229,22 @@ static int rcar_gen3_phy_usb2_power_on(struct phy *p) return 0; } +static int rcar_gen3_phy_usb2_power_off(struct phy *p) +{ + struct rcar_gen3_chan *channel = phy_get_drvdata(p); + int ret = 0; + + if (channel->vbus) + ret = regulator_disable(channel->vbus); + + return ret; +} + static struct phy_ops rcar_gen3_phy_usb2_ops = { .init = rcar_gen3_phy_usb2_init, .exit = rcar_gen3_phy_usb2_exit, .power_on = rcar_gen3_phy_usb2_power_on, + .power_off = rcar_gen3_phy_usb2_power_off, .owner = THIS_MODULE, }; @@ -290,6 +311,13 @@ static int rcar_gen3_phy_usb2_probe(struct platform_device *pdev) return PTR_ERR(channel->phy); } + channel->vbus = devm_regulator_get_optional(dev, "vbus"); + if (IS_ERR(channel->vbus)) { + if (PTR_ERR(channel->vbus) == -EPROBE_DEFER) + return PTR_ERR(channel->vbus); + channel->vbus = NULL; + } + phy_set_drvdata(channel->phy, channel); provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate); -- cgit v1.2.3 From 2b38543c8db1c7dff48aa767fcbfba13f50514ca Mon Sep 17 00:00:00 2001 From: Yoshihiro Shimoda Date: Fri, 29 Apr 2016 14:22:25 +0530 Subject: phy: rcar-gen3-usb2: add extcon support This patch adds extcon support for otg related channel. Signed-off-by: Yoshihiro Shimoda Reviewed-by: Chanwoo Choi Signed-off-by: Kishon Vijay Abraham I --- drivers/phy/Kconfig | 1 + drivers/phy/phy-rcar-gen3-usb2.c | 26 ++++++++++++++++++++++++++ 2 files changed, 27 insertions(+) diff --git a/drivers/phy/Kconfig b/drivers/phy/Kconfig index a72d73cdaef3..447cb7c1a18d 100644 --- a/drivers/phy/Kconfig +++ b/drivers/phy/Kconfig @@ -121,6 +121,7 @@ config PHY_RCAR_GEN2 config PHY_RCAR_GEN3_USB2 tristate "Renesas R-Car generation 3 USB 2.0 PHY driver" depends on ARCH_RENESAS + depends on EXTCON select GENERIC_PHY help Support for USB 2.0 PHY found on Renesas R-Car generation 3 SoCs. diff --git a/drivers/phy/phy-rcar-gen3-usb2.c b/drivers/phy/phy-rcar-gen3-usb2.c index 7b14244be285..76bb88f0700a 100644 --- a/drivers/phy/phy-rcar-gen3-usb2.c +++ b/drivers/phy/phy-rcar-gen3-usb2.c @@ -12,6 +12,7 @@ * published by the Free Software Foundation. */ +#include #include #include #include @@ -77,6 +78,7 @@ struct rcar_gen3_chan { void __iomem *base; + struct extcon_dev *extcon; struct phy *phy; struct regulator *vbus; bool has_otg; @@ -127,6 +129,9 @@ static void rcar_gen3_init_for_host(struct rcar_gen3_chan *ch) rcar_gen3_set_linectrl(ch, 1, 1); rcar_gen3_set_host_mode(ch, 1); rcar_gen3_enable_vbus_ctrl(ch, 1); + + extcon_set_cable_state_(ch->extcon, EXTCON_USB_HOST, true); + extcon_set_cable_state_(ch->extcon, EXTCON_USB, false); } static void rcar_gen3_init_for_peri(struct rcar_gen3_chan *ch) @@ -134,6 +139,9 @@ static void rcar_gen3_init_for_peri(struct rcar_gen3_chan *ch) rcar_gen3_set_linectrl(ch, 0, 1); rcar_gen3_set_host_mode(ch, 0); rcar_gen3_enable_vbus_ctrl(ch, 0); + + extcon_set_cable_state_(ch->extcon, EXTCON_USB_HOST, false); + extcon_set_cable_state_(ch->extcon, EXTCON_USB, true); } static bool rcar_gen3_check_vbus(struct rcar_gen3_chan *ch) @@ -272,6 +280,12 @@ static const struct of_device_id rcar_gen3_phy_usb2_match_table[] = { }; MODULE_DEVICE_TABLE(of, rcar_gen3_phy_usb2_match_table); +static const unsigned int rcar_gen3_phy_cable[] = { + EXTCON_USB, + EXTCON_USB_HOST, + EXTCON_NONE, +}; + static int rcar_gen3_phy_usb2_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; @@ -297,11 +311,23 @@ static int rcar_gen3_phy_usb2_probe(struct platform_device *pdev) /* call request_irq for OTG */ irq = platform_get_irq(pdev, 0); if (irq >= 0) { + int ret; + irq = devm_request_irq(dev, irq, rcar_gen3_phy_usb2_irq, IRQF_SHARED, dev_name(dev), channel); if (irq < 0) dev_err(dev, "No irq handler (%d)\n", irq); channel->has_otg = true; + channel->extcon = devm_extcon_dev_allocate(dev, + rcar_gen3_phy_cable); + if (IS_ERR(channel->extcon)) + return PTR_ERR(channel->extcon); + + ret = devm_extcon_dev_register(dev, channel->extcon); + if (ret < 0) { + dev_err(dev, "Failed to register extcon\n"); + return ret; + } } /* devm_phy_create() will call pm_runtime_enable(dev); */ -- cgit v1.2.3 From 931b119e9432f48e2b384e4d59c33490c5567353 Mon Sep 17 00:00:00 2001 From: Chunfeng Yun Date: Wed, 20 Apr 2016 08:14:01 +0800 Subject: dt-bindings: phy-mt65xx-usb: add support for mt2701 platform Add a new compatible string for "mt2701" Signed-off-by: Chunfeng Yun Reviewed-by: Matthias Brugger Signed-off-by: Kishon Vijay Abraham I --- Documentation/devicetree/bindings/phy/phy-mt65xx-usb.txt | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/phy/phy-mt65xx-usb.txt b/Documentation/devicetree/bindings/phy/phy-mt65xx-usb.txt index 00100cf3e037..33a2b1ee3f3e 100644 --- a/Documentation/devicetree/bindings/phy/phy-mt65xx-usb.txt +++ b/Documentation/devicetree/bindings/phy/phy-mt65xx-usb.txt @@ -4,7 +4,9 @@ mt65xx USB3.0 PHY binding This binding describes a usb3.0 phy for mt65xx platforms of Medaitek SoC. Required properties (controller (parent) node): - - compatible : should be "mediatek,mt8173-u3phy" + - compatible : should be one of + "mediatek,mt2701-u3phy" + "mediatek,mt8173-u3phy" - reg : offset and length of register for phy, exclude port's register. - clocks : a list of phandle + clock-specifier pairs, one for each -- cgit v1.2.3 From e1d76530d7f8f67d0b2a020a2453bed4e8e27b1a Mon Sep 17 00:00:00 2001 From: Chunfeng Yun Date: Wed, 20 Apr 2016 08:14:02 +0800 Subject: phy: phy-mt65xx-usb3: add support for mt2701 platform Add a new OF device ID for mt2701 Some register settings to avoid RX sensitivity level degradation which may arise on mt8173 platform are separated from other platforms. Signed-off-by: Chunfeng Yun Signed-off-by: Kishon Vijay Abraham I --- drivers/phy/Kconfig | 5 ++- drivers/phy/phy-mt65xx-usb3.c | 77 +++++++++++++++++++++++++++++-------------- 2 files changed, 54 insertions(+), 28 deletions(-) diff --git a/drivers/phy/Kconfig b/drivers/phy/Kconfig index 447cb7c1a18d..f6ff76ec89dc 100644 --- a/drivers/phy/Kconfig +++ b/drivers/phy/Kconfig @@ -219,9 +219,8 @@ config PHY_MT65XX_USB3 depends on ARCH_MEDIATEK && OF select GENERIC_PHY help - Say 'Y' here to add support for Mediatek USB3.0 PHY driver - for mt65xx SoCs. it supports two usb2.0 ports and - one usb3.0 port. + Say 'Y' here to add support for Mediatek USB3.0 PHY driver, + it supports multiple usb2.0 and usb3.0 ports. config PHY_HI6220_USB tristate "hi6220 USB PHY support" diff --git a/drivers/phy/phy-mt65xx-usb3.c b/drivers/phy/phy-mt65xx-usb3.c index c0e7b4b0cf5c..4d85e730ccab 100644 --- a/drivers/phy/phy-mt65xx-usb3.c +++ b/drivers/phy/phy-mt65xx-usb3.c @@ -134,6 +134,11 @@ #define U3P_SR_COEF_DIVISOR 1000 #define U3P_FM_DET_CYCLE_CNT 1024 +struct mt65xx_phy_pdata { + /* avoid RX sensitivity level degradation only for mt8173 */ + bool avoid_rx_sen_degradation; +}; + struct mt65xx_phy_instance { struct phy *phy; void __iomem *port_base; @@ -145,6 +150,7 @@ struct mt65xx_u3phy { struct device *dev; void __iomem *sif_base; /* include sif2, but exclude port's */ struct clk *u3phya_ref; /* reference clock of usb3 anolog phy */ + const struct mt65xx_phy_pdata *pdata; struct mt65xx_phy_instance **phys; int nphys; }; @@ -241,22 +247,26 @@ static void phy_instance_init(struct mt65xx_u3phy *u3phy, tmp = readl(port_base + U3P_U2PHYACR4); tmp &= ~P2C_U2_GPIO_CTR_MSK; writel(tmp, port_base + U3P_U2PHYACR4); + } - tmp = readl(port_base + U3P_USBPHYACR2); - tmp |= PA2_RG_SIF_U2PLL_FORCE_EN; - writel(tmp, port_base + U3P_USBPHYACR2); - - tmp = readl(port_base + U3D_U2PHYDCR0); - tmp &= ~P2C_RG_SIF_U2PLL_FORCE_ON; - writel(tmp, port_base + U3D_U2PHYDCR0); - } else { - tmp = readl(port_base + U3D_U2PHYDCR0); - tmp |= P2C_RG_SIF_U2PLL_FORCE_ON; - writel(tmp, port_base + U3D_U2PHYDCR0); - - tmp = readl(port_base + U3P_U2PHYDTM0); - tmp |= P2C_RG_SUSPENDM | P2C_FORCE_SUSPENDM; - writel(tmp, port_base + U3P_U2PHYDTM0); + if (u3phy->pdata->avoid_rx_sen_degradation) { + if (!index) { + tmp = readl(port_base + U3P_USBPHYACR2); + tmp |= PA2_RG_SIF_U2PLL_FORCE_EN; + writel(tmp, port_base + U3P_USBPHYACR2); + + tmp = readl(port_base + U3D_U2PHYDCR0); + tmp &= ~P2C_RG_SIF_U2PLL_FORCE_ON; + writel(tmp, port_base + U3D_U2PHYDCR0); + } else { + tmp = readl(port_base + U3D_U2PHYDCR0); + tmp |= P2C_RG_SIF_U2PLL_FORCE_ON; + writel(tmp, port_base + U3D_U2PHYDCR0); + + tmp = readl(port_base + U3P_U2PHYDTM0); + tmp |= P2C_RG_SUSPENDM | P2C_FORCE_SUSPENDM; + writel(tmp, port_base + U3P_U2PHYDTM0); + } } tmp = readl(port_base + U3P_USBPHYACR6); @@ -318,7 +328,7 @@ static void phy_instance_power_on(struct mt65xx_u3phy *u3phy, tmp |= XC3_RG_U3_XTAL_RX_PWD | XC3_RG_U3_FRC_XTAL_RX_PWD; writel(tmp, u3phy->sif_base + U3P_XTALCTL3); - /* [mt8173]switch 100uA current to SSUSB */ + /* switch 100uA current to SSUSB */ tmp = readl(port_base + U3P_USBPHYACR5); tmp |= PA5_RG_U2_HS_100U_U3_EN; writel(tmp, port_base + U3P_USBPHYACR5); @@ -335,7 +345,7 @@ static void phy_instance_power_on(struct mt65xx_u3phy *u3phy, tmp |= PA5_RG_U2_HSTX_SRCTRL_VAL(4); writel(tmp, port_base + U3P_USBPHYACR5); - if (index) { + if (u3phy->pdata->avoid_rx_sen_degradation && index) { tmp = readl(port_base + U3D_U2PHYDCR0); tmp |= P2C_RG_SIF_U2PLL_FORCE_ON; writel(tmp, port_base + U3D_U2PHYDCR0); @@ -386,7 +396,9 @@ static void phy_instance_power_off(struct mt65xx_u3phy *u3phy, tmp = readl(port_base + U3P_U3_PHYA_REG0); tmp &= ~P3A_RG_U3_VUSB10_ON; writel(tmp, port_base + U3P_U3_PHYA_REG0); - } else { + } + + if (u3phy->pdata->avoid_rx_sen_degradation && index) { tmp = readl(port_base + U3D_U2PHYDCR0); tmp &= ~P2C_RG_SIF_U2PLL_FORCE_ON; writel(tmp, port_base + U3D_U2PHYDCR0); @@ -402,7 +414,7 @@ static void phy_instance_exit(struct mt65xx_u3phy *u3phy, u32 index = instance->index; u32 tmp; - if (index) { + if (u3phy->pdata->avoid_rx_sen_degradation && index) { tmp = readl(port_base + U3D_U2PHYDCR0); tmp &= ~P2C_RG_SIF_U2PLL_FORCE_ON; writel(tmp, port_base + U3D_U2PHYDCR0); @@ -502,8 +514,24 @@ static struct phy_ops mt65xx_u3phy_ops = { .owner = THIS_MODULE, }; +static const struct mt65xx_phy_pdata mt2701_pdata = { + .avoid_rx_sen_degradation = false, +}; + +static const struct mt65xx_phy_pdata mt8173_pdata = { + .avoid_rx_sen_degradation = true, +}; + +static const struct of_device_id mt65xx_u3phy_id_table[] = { + { .compatible = "mediatek,mt2701-u3phy", .data = &mt2701_pdata }, + { .compatible = "mediatek,mt8173-u3phy", .data = &mt8173_pdata }, + { }, +}; +MODULE_DEVICE_TABLE(of, mt65xx_u3phy_id_table); + static int mt65xx_u3phy_probe(struct platform_device *pdev) { + const struct of_device_id *match; struct device *dev = &pdev->dev; struct device_node *np = dev->of_node; struct device_node *child_np; @@ -513,10 +541,15 @@ static int mt65xx_u3phy_probe(struct platform_device *pdev) struct resource res; int port, retval; + match = of_match_node(mt65xx_u3phy_id_table, pdev->dev.of_node); + if (!match) + return -EINVAL; + u3phy = devm_kzalloc(dev, sizeof(*u3phy), GFP_KERNEL); if (!u3phy) return -ENOMEM; + u3phy->pdata = match->data; u3phy->nphys = of_get_child_count(np); u3phy->phys = devm_kcalloc(dev, u3phy->nphys, sizeof(*u3phy->phys), GFP_KERNEL); @@ -587,12 +620,6 @@ put_child: return retval; } -static const struct of_device_id mt65xx_u3phy_id_table[] = { - { .compatible = "mediatek,mt8173-u3phy", }, - { }, -}; -MODULE_DEVICE_TABLE(of, mt65xx_u3phy_id_table); - static struct platform_driver mt65xx_u3phy_driver = { .probe = mt65xx_u3phy_probe, .driver = { -- cgit v1.2.3 From 444525d4f5dd272f695379f5d22660c96ad4fc23 Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Tue, 19 Apr 2016 18:17:26 -0700 Subject: phy: rockhip-usb: Remove CLK_IS_ROOT This flag is a no-op now (see commit 47b0eeb3dc8a "clk: Deprecate CLK_IS_ROOT", 2016-02-02) so remove it. Cc: Heiko Stuebner Signed-off-by: Stephen Boyd Signed-off-by: Kishon Vijay Abraham I --- drivers/phy/phy-rockchip-usb.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/phy/phy-rockchip-usb.c b/drivers/phy/phy-rockchip-usb.c index f62d899063a3..d60b149cff0f 100644 --- a/drivers/phy/phy-rockchip-usb.c +++ b/drivers/phy/phy-rockchip-usb.c @@ -216,7 +216,7 @@ static int rockchip_usb_phy_init(struct rockchip_usb_phy_base *base, init.parent_names = &clk_name; init.num_parents = 1; } else { - init.flags = CLK_IS_ROOT; + init.flags = 0; init.parent_names = NULL; init.num_parents = 0; } -- cgit v1.2.3 From d3feb406733544dbf0e239ef945a09decdceac88 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= Date: Thu, 14 Apr 2016 11:37:43 +0200 Subject: phy: bcm-ns-usb2: new driver for USB 2.0 PHY on Northstar MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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 an EHCI controller driver. There are (just a few) registers being defined in bcma header. It's because DMU/CRU registers will be also needed in other drivers. We will need them e.g. in PCIe controller/PHY driver and at some point probably in clock driver for BCM53573 chipset. By using include/linux/bcma/ we avoid code duplication. Signed-off-by: Rafał Miłecki Signed-off-by: Kishon Vijay Abraham I --- .../devicetree/bindings/phy/bcm-ns-usb2-phy.txt | 21 ++++ drivers/phy/Kconfig | 9 ++ drivers/phy/Makefile | 1 + drivers/phy/phy-bcm-ns-usb2.c | 137 +++++++++++++++++++++ include/linux/bcma/bcma.h | 1 + include/linux/bcma/bcma_driver_arm_c9.h | 15 +++ 6 files changed, 184 insertions(+) create mode 100644 Documentation/devicetree/bindings/phy/bcm-ns-usb2-phy.txt create mode 100644 drivers/phy/phy-bcm-ns-usb2.c create mode 100644 include/linux/bcma/bcma_driver_arm_c9.h diff --git a/Documentation/devicetree/bindings/phy/bcm-ns-usb2-phy.txt b/Documentation/devicetree/bindings/phy/bcm-ns-usb2-phy.txt new file mode 100644 index 000000000000..a7aee9ea8926 --- /dev/null +++ b/Documentation/devicetree/bindings/phy/bcm-ns-usb2-phy.txt @@ -0,0 +1,21 @@ +Driver for Broadcom Northstar USB 2.0 PHY + +Required properties: +- compatible: brcm,ns-usb2-phy +- reg: iomem address range of DMU (Device Management Unit) +- reg-names: "dmu", the only needed & supported reg right now +- clocks: USB PHY reference clock +- clock-names: "phy-ref-clk", the only needed & supported clock right now + +To initialize USB 2.0 PHY driver needs to setup PLL correctly. To do this it +requires passing phandle to the USB PHY reference clock. + +Example: + usb2-phy { + compatible = "brcm,ns-usb2-phy"; + reg = <0x1800c000 0x1000>; + reg-names = "dmu"; + #phy-cells = <0>; + clocks = <&genpll BCM_NSP_GENPLL_USB_PHY_REF_CLK>; + clock-names = "phy-ref-clk"; + }; diff --git a/drivers/phy/Kconfig b/drivers/phy/Kconfig index f6ff76ec89dc..f2b458fc0c89 100644 --- a/drivers/phy/Kconfig +++ b/drivers/phy/Kconfig @@ -15,6 +15,15 @@ config GENERIC_PHY phy users can obtain reference to the PHY. All the users of this framework should select this config. +config PHY_BCM_NS_USB2 + tristate "Broadcom Northstar USB 2.0 PHY Driver" + depends on ARCH_BCM_IPROC || COMPILE_TEST + depends on HAS_IOMEM && OF + select GENERIC_PHY + help + Enable this to support Broadcom USB 2.0 PHY connected to the USB + controller on Northstar family. + config PHY_BERLIN_USB tristate "Marvell Berlin USB PHY Driver" depends on ARCH_BERLIN && RESET_CONTROLLER && HAS_IOMEM && OF diff --git a/drivers/phy/Makefile b/drivers/phy/Makefile index f03fa1fdf322..0de09e13fdbc 100644 --- a/drivers/phy/Makefile +++ b/drivers/phy/Makefile @@ -3,6 +3,7 @@ # obj-$(CONFIG_GENERIC_PHY) += phy-core.o +obj-$(CONFIG_PHY_BCM_NS_USB2) += phy-bcm-ns-usb2.o obj-$(CONFIG_PHY_BERLIN_USB) += phy-berlin-usb.o obj-$(CONFIG_PHY_BERLIN_SATA) += phy-berlin-sata.o obj-$(CONFIG_PHY_DM816X_USB) += phy-dm816x-usb.o diff --git a/drivers/phy/phy-bcm-ns-usb2.c b/drivers/phy/phy-bcm-ns-usb2.c new file mode 100644 index 000000000000..95ab6b2a0de5 --- /dev/null +++ b/drivers/phy/phy-bcm-ns-usb2.c @@ -0,0 +1,137 @@ +/* + * Broadcom Northstar USB 2.0 PHY Driver + * + * Copyright (C) 2016 Rafał Miłecki + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include + +struct bcm_ns_usb2 { + struct device *dev; + struct clk *ref_clk; + struct phy *phy; + void __iomem *dmu; +}; + +static int bcm_ns_usb2_phy_init(struct phy *phy) +{ + struct bcm_ns_usb2 *usb2 = phy_get_drvdata(phy); + struct device *dev = usb2->dev; + void __iomem *dmu = usb2->dmu; + u32 ref_clk_rate, usb2ctl, usb_pll_ndiv, usb_pll_pdiv; + int err = 0; + + err = clk_prepare_enable(usb2->ref_clk); + if (err < 0) { + dev_err(dev, "Failed to prepare ref clock: %d\n", err); + goto err_out; + } + + ref_clk_rate = clk_get_rate(usb2->ref_clk); + if (!ref_clk_rate) { + dev_err(dev, "Failed to get ref clock rate\n"); + err = -EINVAL; + goto err_clk_off; + } + + usb2ctl = readl(dmu + BCMA_DMU_CRU_USB2_CONTROL); + + if (usb2ctl & BCMA_DMU_CRU_USB2_CONTROL_USB_PLL_PDIV_MASK) { + usb_pll_pdiv = usb2ctl; + usb_pll_pdiv &= BCMA_DMU_CRU_USB2_CONTROL_USB_PLL_PDIV_MASK; + usb_pll_pdiv >>= BCMA_DMU_CRU_USB2_CONTROL_USB_PLL_PDIV_SHIFT; + } else { + usb_pll_pdiv = 1 << 3; + } + + /* Calculate ndiv based on a solid 1920 MHz that is for USB2 PHY */ + usb_pll_ndiv = (1920000000 * usb_pll_pdiv) / ref_clk_rate; + + /* Unlock DMU PLL settings with some magic value */ + writel(0x0000ea68, dmu + BCMA_DMU_CRU_CLKSET_KEY); + + /* Write USB 2.0 PLL control setting */ + usb2ctl &= ~BCMA_DMU_CRU_USB2_CONTROL_USB_PLL_NDIV_MASK; + usb2ctl |= usb_pll_ndiv << BCMA_DMU_CRU_USB2_CONTROL_USB_PLL_NDIV_SHIFT; + writel(usb2ctl, dmu + BCMA_DMU_CRU_USB2_CONTROL); + + /* Lock DMU PLL settings */ + writel(0x00000000, dmu + BCMA_DMU_CRU_CLKSET_KEY); + +err_clk_off: + clk_disable_unprepare(usb2->ref_clk); +err_out: + return err; +} + +static const struct phy_ops ops = { + .init = bcm_ns_usb2_phy_init, + .owner = THIS_MODULE, +}; + +static int bcm_ns_usb2_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct bcm_ns_usb2 *usb2; + struct resource *res; + struct phy_provider *phy_provider; + + usb2 = devm_kzalloc(&pdev->dev, sizeof(*usb2), GFP_KERNEL); + if (!usb2) + return -ENOMEM; + usb2->dev = dev; + + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "dmu"); + usb2->dmu = devm_ioremap_resource(dev, res); + if (IS_ERR(usb2->dmu)) { + dev_err(dev, "Failed to map DMU regs\n"); + return PTR_ERR(usb2->dmu); + } + + usb2->ref_clk = devm_clk_get(dev, "phy-ref-clk"); + if (IS_ERR(usb2->ref_clk)) { + dev_err(dev, "Clock not defined\n"); + return PTR_ERR(usb2->ref_clk); + } + + usb2->phy = devm_phy_create(dev, NULL, &ops); + if (IS_ERR(dev)) + return PTR_ERR(dev); + + phy_set_drvdata(usb2->phy, usb2); + platform_set_drvdata(pdev, usb2); + + phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate); + return PTR_ERR_OR_ZERO(phy_provider); +} + +static const struct of_device_id bcm_ns_usb2_id_table[] = { + { .compatible = "brcm,ns-usb2-phy", }, + {}, +}; +MODULE_DEVICE_TABLE(of, bcm_ns_usb2_id_table); + +static struct platform_driver bcm_ns_usb2_driver = { + .probe = bcm_ns_usb2_probe, + .driver = { + .name = "bcm_ns_usb2", + .of_match_table = bcm_ns_usb2_id_table, + }, +}; +module_platform_driver(bcm_ns_usb2_driver); + +MODULE_LICENSE("GPL v2"); diff --git a/include/linux/bcma/bcma.h b/include/linux/bcma/bcma.h index 0367c63f5960..e6b41f42602b 100644 --- a/include/linux/bcma/bcma.h +++ b/include/linux/bcma/bcma.h @@ -4,6 +4,7 @@ #include #include +#include #include #include #include diff --git a/include/linux/bcma/bcma_driver_arm_c9.h b/include/linux/bcma/bcma_driver_arm_c9.h new file mode 100644 index 000000000000..93bd73d670d5 --- /dev/null +++ b/include/linux/bcma/bcma_driver_arm_c9.h @@ -0,0 +1,15 @@ +#ifndef LINUX_BCMA_DRIVER_ARM_C9_H_ +#define LINUX_BCMA_DRIVER_ARM_C9_H_ + +/* DMU (Device Management Unit) */ +#define BCMA_DMU_CRU_USB2_CONTROL 0x0164 +#define BCMA_DMU_CRU_USB2_CONTROL_USB_PLL_NDIV_MASK 0x00000FFC +#define BCMA_DMU_CRU_USB2_CONTROL_USB_PLL_NDIV_SHIFT 2 +#define BCMA_DMU_CRU_USB2_CONTROL_USB_PLL_PDIV_MASK 0x00007000 +#define BCMA_DMU_CRU_USB2_CONTROL_USB_PLL_PDIV_SHIFT 12 +#define BCMA_DMU_CRU_CLKSET_KEY 0x0180 +#define BCMA_DMU_CRU_STRAPS_CTRL 0x02A0 +#define BCMA_DMU_CRU_STRAPS_CTRL_USB3 0x00000010 +#define BCMA_DMU_CRU_STRAPS_CTRL_4BYTE 0x00008000 + +#endif /* LINUX_BCMA_DRIVER_ARM_C9_H_ */ -- cgit v1.2.3 From 26dbadba495fa69b041a7f1ceaa8c48c26178e34 Mon Sep 17 00:00:00 2001 From: Sylwester Nawrocki Date: Wed, 23 Mar 2016 12:09:16 +0100 Subject: phy: exynos-mipi-video: Drop support for direct access to PMU There is no need to support access to the PMU through memory ioresource as now access through PMU regmap should only be used. Signed-off-by: Sylwester Nawrocki Signed-off-by: Marek Szyprowski Signed-off-by: Kishon Vijay Abraham I --- drivers/phy/phy-exynos-mipi-video.c | 57 +++++++++---------------------------- 1 file changed, 13 insertions(+), 44 deletions(-) diff --git a/drivers/phy/phy-exynos-mipi-video.c b/drivers/phy/phy-exynos-mipi-video.c index 2a54caba93b4..d4f5d8e6afbf 100644 --- a/drivers/phy/phy-exynos-mipi-video.c +++ b/drivers/phy/phy-exynos-mipi-video.c @@ -22,9 +22,6 @@ #include #include -/* MIPI_PHYn_CONTROL reg. offset (for base address from ioremap): n = 0..1 */ -#define EXYNOS_MIPI_PHY_CONTROL(n) ((n) * 4) - enum exynos_mipi_phy_id { EXYNOS_MIPI_PHY_ID_CSIS0, EXYNOS_MIPI_PHY_ID_DSIM0, @@ -50,7 +47,6 @@ static int __set_phy_state(struct exynos_mipi_video_phy *state, enum exynos_mipi_phy_id id, unsigned int on) { const unsigned int offset = EXYNOS4_MIPI_PHY_CONTROL(id / 2); - void __iomem *addr; u32 val, reset; if (is_mipi_dsim_phy_id(id)) @@ -60,35 +56,17 @@ static int __set_phy_state(struct exynos_mipi_video_phy *state, spin_lock(&state->slock); - if (!IS_ERR(state->regmap)) { - regmap_read(state->regmap, offset, &val); - if (on) - val |= reset; - else - val &= ~reset; - regmap_write(state->regmap, offset, val); - if (on) - val |= EXYNOS4_MIPI_PHY_ENABLE; - else if (!(val & EXYNOS4_MIPI_PHY_RESET_MASK)) - val &= ~EXYNOS4_MIPI_PHY_ENABLE; - regmap_write(state->regmap, offset, val); - } else { - addr = state->regs + EXYNOS_MIPI_PHY_CONTROL(id / 2); - - val = readl(addr); - if (on) - val |= reset; - else - val &= ~reset; - writel(val, addr); - /* Clear ENABLE bit only if MRESETN, SRESETN bits are not set */ - if (on) - val |= EXYNOS4_MIPI_PHY_ENABLE; - else if (!(val & EXYNOS4_MIPI_PHY_RESET_MASK)) - val &= ~EXYNOS4_MIPI_PHY_ENABLE; - - writel(val, addr); - } + regmap_read(state->regmap, offset, &val); + if (on) + val |= reset; + else + val &= ~reset; + regmap_write(state->regmap, offset, val); + if (on) + val |= EXYNOS4_MIPI_PHY_ENABLE; + else if (!(val & EXYNOS4_MIPI_PHY_RESET_MASK)) + val &= ~EXYNOS4_MIPI_PHY_ENABLE; + regmap_write(state->regmap, offset, val); spin_unlock(&state->slock); return 0; @@ -142,17 +120,8 @@ static int exynos_mipi_video_phy_probe(struct platform_device *pdev) return -ENOMEM; state->regmap = syscon_regmap_lookup_by_phandle(dev->of_node, "syscon"); - if (IS_ERR(state->regmap)) { - struct resource *res; - - dev_info(dev, "regmap lookup failed: %ld\n", - PTR_ERR(state->regmap)); - - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - state->regs = devm_ioremap_resource(dev, res); - if (IS_ERR(state->regs)) - return PTR_ERR(state->regs); - } + if (IS_ERR(state->regmap)) + return PTR_ERR(state->regmap); dev_set_drvdata(dev, state); spin_lock_init(&state->slock); -- cgit v1.2.3 From 97a3042f76164330f7ac5dbe7434f63f92d6f09d Mon Sep 17 00:00:00 2001 From: Marek Szyprowski Date: Wed, 23 Mar 2016 12:09:17 +0100 Subject: phy: exynos-mipi-video: Rewrite handling of phy registers Controlling Exynos MIPI DPHY is done by handling 2 registers: one for phy reset and one for enabling it. This patch moves definitions of those 2 registers to speparate exynos_mipi_phy_desc structure, which can be defined separately for each PHY for each supported hardware variant. This code rewrite is needed to add support for newer Exynos SoCs, which have MIPI PHY related registers at different offsets or even different register regions. Acked-by: Sylwester Nawrocki Signed-off-by: Marek Szyprowski Signed-off-by: Kishon Vijay Abraham I --- drivers/phy/phy-exynos-mipi-video.c | 165 ++++++++++++++++++++++++++++-------- 1 file changed, 130 insertions(+), 35 deletions(-) diff --git a/drivers/phy/phy-exynos-mipi-video.c b/drivers/phy/phy-exynos-mipi-video.c index d4f5d8e6afbf..3cb69e005f18 100644 --- a/drivers/phy/phy-exynos-mipi-video.c +++ b/drivers/phy/phy-exynos-mipi-video.c @@ -16,13 +16,14 @@ #include #include #include +#include #include -#include #include #include #include enum exynos_mipi_phy_id { + EXYNOS_MIPI_PHY_ID_NONE = -1, EXYNOS_MIPI_PHY_ID_CSIS0, EXYNOS_MIPI_PHY_ID_DSIM0, EXYNOS_MIPI_PHY_ID_CSIS1, @@ -30,57 +31,137 @@ enum exynos_mipi_phy_id { EXYNOS_MIPI_PHYS_NUM }; -#define is_mipi_dsim_phy_id(id) \ - ((id) == EXYNOS_MIPI_PHY_ID_DSIM0 || (id) == EXYNOS_MIPI_PHY_ID_DSIM1) +enum exynos_mipi_phy_regmap_id { + EXYNOS_MIPI_REGMAP_PMU, + EXYNOS_MIPI_REGMAPS_NUM +}; + +struct mipi_phy_device_desc { + int num_phys; + int num_regmaps; + const char *regmap_names[EXYNOS_MIPI_REGMAPS_NUM]; + struct exynos_mipi_phy_desc { + enum exynos_mipi_phy_id coupled_phy_id; + u32 enable_val; + unsigned int enable_reg; + enum exynos_mipi_phy_regmap_id enable_map; + u32 resetn_val; + unsigned int resetn_reg; + enum exynos_mipi_phy_regmap_id resetn_map; + } phys[EXYNOS_MIPI_PHYS_NUM]; +}; + +static const struct mipi_phy_device_desc s5pv210_mipi_phy = { + .num_regmaps = 1, + .regmap_names = {"syscon"}, + .num_phys = 4, + .phys = { + { + /* EXYNOS_MIPI_PHY_ID_CSIS0 */ + .coupled_phy_id = EXYNOS_MIPI_PHY_ID_DSIM0, + .enable_val = EXYNOS4_MIPI_PHY_ENABLE, + .enable_reg = EXYNOS4_MIPI_PHY_CONTROL(0), + .enable_map = EXYNOS_MIPI_REGMAP_PMU, + .resetn_val = EXYNOS4_MIPI_PHY_SRESETN, + .resetn_reg = EXYNOS4_MIPI_PHY_CONTROL(0), + .resetn_map = EXYNOS_MIPI_REGMAP_PMU, + }, { + /* EXYNOS_MIPI_PHY_ID_DSIM0 */ + .coupled_phy_id = EXYNOS_MIPI_PHY_ID_CSIS0, + .enable_val = EXYNOS4_MIPI_PHY_ENABLE, + .enable_reg = EXYNOS4_MIPI_PHY_CONTROL(0), + .enable_map = EXYNOS_MIPI_REGMAP_PMU, + .resetn_val = EXYNOS4_MIPI_PHY_MRESETN, + .resetn_reg = EXYNOS4_MIPI_PHY_CONTROL(0), + .resetn_map = EXYNOS_MIPI_REGMAP_PMU, + }, { + /* EXYNOS_MIPI_PHY_ID_CSIS1 */ + .coupled_phy_id = EXYNOS_MIPI_PHY_ID_DSIM1, + .enable_val = EXYNOS4_MIPI_PHY_ENABLE, + .enable_reg = EXYNOS4_MIPI_PHY_CONTROL(1), + .enable_map = EXYNOS_MIPI_REGMAP_PMU, + .resetn_val = EXYNOS4_MIPI_PHY_SRESETN, + .resetn_reg = EXYNOS4_MIPI_PHY_CONTROL(1), + .resetn_map = EXYNOS_MIPI_REGMAP_PMU, + }, { + /* EXYNOS_MIPI_PHY_ID_DSIM1 */ + .coupled_phy_id = EXYNOS_MIPI_PHY_ID_CSIS1, + .enable_val = EXYNOS4_MIPI_PHY_ENABLE, + .enable_reg = EXYNOS4_MIPI_PHY_CONTROL(1), + .enable_map = EXYNOS_MIPI_REGMAP_PMU, + .resetn_val = EXYNOS4_MIPI_PHY_MRESETN, + .resetn_reg = EXYNOS4_MIPI_PHY_CONTROL(1), + .resetn_map = EXYNOS_MIPI_REGMAP_PMU, + }, + }, +}; + struct exynos_mipi_video_phy { + struct regmap *regmaps[EXYNOS_MIPI_REGMAPS_NUM]; + int num_phys; struct video_phy_desc { struct phy *phy; unsigned int index; + const struct exynos_mipi_phy_desc *data; } phys[EXYNOS_MIPI_PHYS_NUM]; spinlock_t slock; - void __iomem *regs; - struct regmap *regmap; }; -static int __set_phy_state(struct exynos_mipi_video_phy *state, - enum exynos_mipi_phy_id id, unsigned int on) +static inline int __is_running(const struct exynos_mipi_phy_desc *data, + struct exynos_mipi_video_phy *state) { - const unsigned int offset = EXYNOS4_MIPI_PHY_CONTROL(id / 2); - u32 val, reset; + u32 val; - if (is_mipi_dsim_phy_id(id)) - reset = EXYNOS4_MIPI_PHY_MRESETN; - else - reset = EXYNOS4_MIPI_PHY_SRESETN; + regmap_read(state->regmaps[data->resetn_map], data->resetn_reg, &val); + return val & data->resetn_val; +} + +static int __set_phy_state(const struct exynos_mipi_phy_desc *data, + struct exynos_mipi_video_phy *state, unsigned int on) +{ + u32 val; spin_lock(&state->slock); - regmap_read(state->regmap, offset, &val); - if (on) - val |= reset; - else - val &= ~reset; - regmap_write(state->regmap, offset, val); - if (on) - val |= EXYNOS4_MIPI_PHY_ENABLE; - else if (!(val & EXYNOS4_MIPI_PHY_RESET_MASK)) - val &= ~EXYNOS4_MIPI_PHY_ENABLE; - regmap_write(state->regmap, offset, val); + /* disable in PMU sysreg */ + if (!on && data->coupled_phy_id >= 0 && + !__is_running(state->phys[data->coupled_phy_id].data, state)) { + regmap_read(state->regmaps[data->enable_map], data->enable_reg, + &val); + val &= ~data->enable_val; + regmap_write(state->regmaps[data->enable_map], data->enable_reg, + val); + } + + /* PHY reset */ + regmap_read(state->regmaps[data->resetn_map], data->resetn_reg, &val); + val = on ? (val | data->resetn_val) : (val & ~data->resetn_val); + regmap_write(state->regmaps[data->resetn_map], data->resetn_reg, val); + + /* enable in PMU sysreg */ + if (on) { + regmap_read(state->regmaps[data->enable_map], data->enable_reg, + &val); + val |= data->enable_val; + regmap_write(state->regmaps[data->enable_map], data->enable_reg, + val); + } spin_unlock(&state->slock); + return 0; } #define to_mipi_video_phy(desc) \ - container_of((desc), struct exynos_mipi_video_phy, phys[(desc)->index]); + container_of((desc), struct exynos_mipi_video_phy, phys[(desc)->index]) static int exynos_mipi_video_phy_power_on(struct phy *phy) { struct video_phy_desc *phy_desc = phy_get_drvdata(phy); struct exynos_mipi_video_phy *state = to_mipi_video_phy(phy_desc); - return __set_phy_state(state, phy_desc->index, 1); + return __set_phy_state(phy_desc->data, state, 1); } static int exynos_mipi_video_phy_power_off(struct phy *phy) @@ -88,7 +169,7 @@ static int exynos_mipi_video_phy_power_off(struct phy *phy) struct video_phy_desc *phy_desc = phy_get_drvdata(phy); struct exynos_mipi_video_phy *state = to_mipi_video_phy(phy_desc); - return __set_phy_state(state, phy_desc->index, 0); + return __set_phy_state(phy_desc->data, state, 0); } static struct phy *exynos_mipi_video_phy_xlate(struct device *dev, @@ -96,7 +177,7 @@ static struct phy *exynos_mipi_video_phy_xlate(struct device *dev, { struct exynos_mipi_video_phy *state = dev_get_drvdata(dev); - if (WARN_ON(args->args[0] >= EXYNOS_MIPI_PHYS_NUM)) + if (WARN_ON(args->args[0] >= state->num_phys)) return ERR_PTR(-ENODEV); return state->phys[args->args[0]].phy; @@ -110,23 +191,33 @@ static const struct phy_ops exynos_mipi_video_phy_ops = { static int exynos_mipi_video_phy_probe(struct platform_device *pdev) { + const struct mipi_phy_device_desc *phy_dev; struct exynos_mipi_video_phy *state; struct device *dev = &pdev->dev; + struct device_node *np = dev->of_node; struct phy_provider *phy_provider; unsigned int i; + phy_dev = of_device_get_match_data(dev); + if (!phy_dev) + return -ENODEV; + state = devm_kzalloc(dev, sizeof(*state), GFP_KERNEL); if (!state) return -ENOMEM; - state->regmap = syscon_regmap_lookup_by_phandle(dev->of_node, "syscon"); - if (IS_ERR(state->regmap)) - return PTR_ERR(state->regmap); + for (i = 0; i < phy_dev->num_regmaps; i++) { + state->regmaps[i] = syscon_regmap_lookup_by_phandle(np, + phy_dev->regmap_names[i]); + if (IS_ERR(state->regmaps[i])) + return PTR_ERR(state->regmaps[i]); + } + state->num_phys = phy_dev->num_phys; + spin_lock_init(&state->slock); dev_set_drvdata(dev, state); - spin_lock_init(&state->slock); - for (i = 0; i < EXYNOS_MIPI_PHYS_NUM; i++) { + for (i = 0; i < state->num_phys; i++) { struct phy *phy = devm_phy_create(dev, NULL, &exynos_mipi_video_phy_ops); if (IS_ERR(phy)) { @@ -136,6 +227,7 @@ static int exynos_mipi_video_phy_probe(struct platform_device *pdev) state->phys[i].phy = phy; state->phys[i].index = i; + state->phys[i].data = &phy_dev->phys[i]; phy_set_drvdata(phy, &state->phys[i]); } @@ -146,8 +238,11 @@ static int exynos_mipi_video_phy_probe(struct platform_device *pdev) } static const struct of_device_id exynos_mipi_video_phy_of_match[] = { - { .compatible = "samsung,s5pv210-mipi-video-phy" }, - { }, + { + .compatible = "samsung,s5pv210-mipi-video-phy", + .data = &s5pv210_mipi_phy, + }, + { /* sentinel */ }, }; MODULE_DEVICE_TABLE(of, exynos_mipi_video_phy_of_match); -- cgit v1.2.3 From 71f5c63c07e5be7abdce40891778ffbf3cec04f0 Mon Sep 17 00:00:00 2001 From: Marek Szyprowski Date: Wed, 23 Mar 2016 12:09:18 +0100 Subject: phy: exynos-mipi-video: Add support for Exynos 5420 and 5433 SoCs This patch adds support for MIPI DPHYs found in Exynos5420-compatible (5420, 5422 and 5800) and Exynos5433 SoCs. Those SoCs differs from earlier by different offset of MIPI DPHY registers in PMU controllers (Exynos 5420-compatible case) or by moving MIPI DPHY reset registers to separate system register controllers (Exynos 5433 case). In both case also additional 5th PHY (MIPI CSIS 2) has been added. Acked-by: Sylwester Nawrocki Signed-off-by: Marek Szyprowski Signed-off-by: Kishon Vijay Abraham I --- .../devicetree/bindings/phy/samsung-phy.txt | 18 ++- drivers/phy/phy-exynos-mipi-video.c | 129 ++++++++++++++++++++- include/linux/mfd/syscon/exynos5-pmu.h | 3 + 3 files changed, 147 insertions(+), 3 deletions(-) diff --git a/Documentation/devicetree/bindings/phy/samsung-phy.txt b/Documentation/devicetree/bindings/phy/samsung-phy.txt index 0289d3b07853..9872ba8546bd 100644 --- a/Documentation/devicetree/bindings/phy/samsung-phy.txt +++ b/Documentation/devicetree/bindings/phy/samsung-phy.txt @@ -2,9 +2,20 @@ Samsung S5P/EXYNOS SoC series MIPI CSIS/DSIM DPHY ------------------------------------------------- Required properties: -- compatible : should be "samsung,s5pv210-mipi-video-phy"; +- compatible : should be one of the listed compatibles: + - "samsung,s5pv210-mipi-video-phy" + - "samsung,exynos5420-mipi-video-phy" + - "samsung,exynos5433-mipi-video-phy" - #phy-cells : from the generic phy bindings, must be 1; -- syscon - phandle to the PMU system controller; + +In case of s5pv210 and exynos5420 compatible PHYs: +- syscon - phandle to the PMU system controller + +In case of exynos5433 compatible PHY: + - samsung,pmu-syscon - phandle to the PMU system controller + - samsung,disp-sysreg - phandle to the DISP system registers controller + - samsung,cam0-sysreg - phandle to the CAM0 system registers controller + - samsung,cam1-sysreg - phandle to the CAM1 system registers controller For "samsung,s5pv210-mipi-video-phy" compatible PHYs the second cell in the PHY specifier identifies the PHY and its meaning is as follows: @@ -12,6 +23,9 @@ the PHY specifier identifies the PHY and its meaning is as follows: 1 - MIPI DSIM 0, 2 - MIPI CSIS 1, 3 - MIPI DSIM 1. +"samsung,exynos5420-mipi-video-phy" and "samsung,exynos5433-mipi-video-phy" +supports additional fifth PHY: + 4 - MIPI CSIS 2. Samsung EXYNOS SoC series Display Port PHY ------------------------------------------------- diff --git a/drivers/phy/phy-exynos-mipi-video.c b/drivers/phy/phy-exynos-mipi-video.c index 3cb69e005f18..cc093ebfda94 100644 --- a/drivers/phy/phy-exynos-mipi-video.c +++ b/drivers/phy/phy-exynos-mipi-video.c @@ -1,7 +1,7 @@ /* * Samsung S5P/EXYNOS SoC series MIPI CSIS/DSIM DPHY driver * - * Copyright (C) 2013 Samsung Electronics Co., Ltd. + * Copyright (C) 2013,2016 Samsung Electronics Co., Ltd. * Author: Sylwester Nawrocki * * This program is free software; you can redistribute it and/or modify @@ -13,6 +13,7 @@ #include #include #include +#include #include #include #include @@ -28,11 +29,15 @@ enum exynos_mipi_phy_id { EXYNOS_MIPI_PHY_ID_DSIM0, EXYNOS_MIPI_PHY_ID_CSIS1, EXYNOS_MIPI_PHY_ID_DSIM1, + EXYNOS_MIPI_PHY_ID_CSIS2, EXYNOS_MIPI_PHYS_NUM }; enum exynos_mipi_phy_regmap_id { EXYNOS_MIPI_REGMAP_PMU, + EXYNOS_MIPI_REGMAP_DISP, + EXYNOS_MIPI_REGMAP_CAM0, + EXYNOS_MIPI_REGMAP_CAM1, EXYNOS_MIPI_REGMAPS_NUM }; @@ -96,6 +101,122 @@ static const struct mipi_phy_device_desc s5pv210_mipi_phy = { }, }; +static const struct mipi_phy_device_desc exynos5420_mipi_phy = { + .num_regmaps = 1, + .regmap_names = {"syscon"}, + .num_phys = 5, + .phys = { + { + /* EXYNOS_MIPI_PHY_ID_CSIS0 */ + .coupled_phy_id = EXYNOS_MIPI_PHY_ID_DSIM0, + .enable_val = EXYNOS5_PHY_ENABLE, + .enable_reg = EXYNOS5420_MIPI_PHY0_CONTROL, + .enable_map = EXYNOS_MIPI_REGMAP_PMU, + .resetn_val = EXYNOS5_MIPI_PHY_S_RESETN, + .resetn_reg = EXYNOS5420_MIPI_PHY0_CONTROL, + .resetn_map = EXYNOS_MIPI_REGMAP_PMU, + }, { + /* EXYNOS_MIPI_PHY_ID_DSIM0 */ + .coupled_phy_id = EXYNOS_MIPI_PHY_ID_CSIS0, + .enable_val = EXYNOS5_PHY_ENABLE, + .enable_reg = EXYNOS5420_MIPI_PHY0_CONTROL, + .enable_map = EXYNOS_MIPI_REGMAP_PMU, + .resetn_val = EXYNOS5_MIPI_PHY_M_RESETN, + .resetn_reg = EXYNOS5420_MIPI_PHY0_CONTROL, + .resetn_map = EXYNOS_MIPI_REGMAP_PMU, + }, { + /* EXYNOS_MIPI_PHY_ID_CSIS1 */ + .coupled_phy_id = EXYNOS_MIPI_PHY_ID_DSIM1, + .enable_val = EXYNOS5_PHY_ENABLE, + .enable_reg = EXYNOS5420_MIPI_PHY1_CONTROL, + .enable_map = EXYNOS_MIPI_REGMAP_PMU, + .resetn_val = EXYNOS5_MIPI_PHY_S_RESETN, + .resetn_reg = EXYNOS5420_MIPI_PHY1_CONTROL, + .resetn_map = EXYNOS_MIPI_REGMAP_PMU, + }, { + /* EXYNOS_MIPI_PHY_ID_DSIM1 */ + .coupled_phy_id = EXYNOS_MIPI_PHY_ID_CSIS1, + .enable_val = EXYNOS5_PHY_ENABLE, + .enable_reg = EXYNOS5420_MIPI_PHY1_CONTROL, + .enable_map = EXYNOS_MIPI_REGMAP_PMU, + .resetn_val = EXYNOS5_MIPI_PHY_M_RESETN, + .resetn_reg = EXYNOS5420_MIPI_PHY1_CONTROL, + .resetn_map = EXYNOS_MIPI_REGMAP_PMU, + }, { + /* EXYNOS_MIPI_PHY_ID_CSIS2 */ + .coupled_phy_id = EXYNOS_MIPI_PHY_ID_NONE, + .enable_val = EXYNOS5_PHY_ENABLE, + .enable_reg = EXYNOS5420_MIPI_PHY2_CONTROL, + .enable_map = EXYNOS_MIPI_REGMAP_PMU, + .resetn_val = EXYNOS5_MIPI_PHY_S_RESETN, + .resetn_reg = EXYNOS5420_MIPI_PHY2_CONTROL, + .resetn_map = EXYNOS_MIPI_REGMAP_PMU, + }, + }, +}; + +#define EXYNOS5433_SYSREG_DISP_MIPI_PHY 0x100C +#define EXYNOS5433_SYSREG_CAM0_MIPI_DPHY_CON 0x1014 +#define EXYNOS5433_SYSREG_CAM1_MIPI_DPHY_CON 0x1020 + +static const struct mipi_phy_device_desc exynos5433_mipi_phy = { + .num_regmaps = 4, + .regmap_names = { + "samsung,pmu-syscon", + "samsung,disp-sysreg", + "samsung,cam0-sysreg", + "samsung,cam1-sysreg" + }, + .num_phys = 5, + .phys = { + { + /* EXYNOS_MIPI_PHY_ID_CSIS0 */ + .coupled_phy_id = EXYNOS_MIPI_PHY_ID_DSIM0, + .enable_val = EXYNOS5_PHY_ENABLE, + .enable_reg = EXYNOS5433_MIPI_PHY0_CONTROL, + .enable_map = EXYNOS_MIPI_REGMAP_PMU, + .resetn_val = BIT(0), + .resetn_reg = EXYNOS5433_SYSREG_CAM0_MIPI_DPHY_CON, + .resetn_map = EXYNOS_MIPI_REGMAP_CAM0, + }, { + /* EXYNOS_MIPI_PHY_ID_DSIM0 */ + .coupled_phy_id = EXYNOS_MIPI_PHY_ID_CSIS0, + .enable_val = EXYNOS5_PHY_ENABLE, + .enable_reg = EXYNOS5433_MIPI_PHY0_CONTROL, + .enable_map = EXYNOS_MIPI_REGMAP_PMU, + .resetn_val = BIT(0), + .resetn_reg = EXYNOS5433_SYSREG_DISP_MIPI_PHY, + .resetn_map = EXYNOS_MIPI_REGMAP_DISP, + }, { + /* EXYNOS_MIPI_PHY_ID_CSIS1 */ + .coupled_phy_id = EXYNOS_MIPI_PHY_ID_NONE, + .enable_val = EXYNOS5_PHY_ENABLE, + .enable_reg = EXYNOS5433_MIPI_PHY1_CONTROL, + .enable_map = EXYNOS_MIPI_REGMAP_PMU, + .resetn_val = BIT(1), + .resetn_reg = EXYNOS5433_SYSREG_CAM0_MIPI_DPHY_CON, + .resetn_map = EXYNOS_MIPI_REGMAP_CAM0, + }, { + /* EXYNOS_MIPI_PHY_ID_DSIM1 */ + .coupled_phy_id = EXYNOS_MIPI_PHY_ID_NONE, + .enable_val = EXYNOS5_PHY_ENABLE, + .enable_reg = EXYNOS5433_MIPI_PHY1_CONTROL, + .enable_map = EXYNOS_MIPI_REGMAP_PMU, + .resetn_val = BIT(1), + .resetn_reg = EXYNOS5433_SYSREG_DISP_MIPI_PHY, + .resetn_map = EXYNOS_MIPI_REGMAP_DISP, + }, { + /* EXYNOS_MIPI_PHY_ID_CSIS2 */ + .coupled_phy_id = EXYNOS_MIPI_PHY_ID_NONE, + .enable_val = EXYNOS5_PHY_ENABLE, + .enable_reg = EXYNOS5433_MIPI_PHY2_CONTROL, + .enable_map = EXYNOS_MIPI_REGMAP_PMU, + .resetn_val = BIT(0), + .resetn_reg = EXYNOS5433_SYSREG_CAM1_MIPI_DPHY_CON, + .resetn_map = EXYNOS_MIPI_REGMAP_CAM1, + }, + }, +}; struct exynos_mipi_video_phy { struct regmap *regmaps[EXYNOS_MIPI_REGMAPS_NUM]; @@ -241,6 +362,12 @@ static const struct of_device_id exynos_mipi_video_phy_of_match[] = { { .compatible = "samsung,s5pv210-mipi-video-phy", .data = &s5pv210_mipi_phy, + }, { + .compatible = "samsung,exynos5420-mipi-video-phy", + .data = &exynos5420_mipi_phy, + }, { + .compatible = "samsung,exynos5433-mipi-video-phy", + .data = &exynos5433_mipi_phy, }, { /* sentinel */ }, }; diff --git a/include/linux/mfd/syscon/exynos5-pmu.h b/include/linux/mfd/syscon/exynos5-pmu.h index 9352adc95de6..76f30f940c70 100644 --- a/include/linux/mfd/syscon/exynos5-pmu.h +++ b/include/linux/mfd/syscon/exynos5-pmu.h @@ -38,6 +38,9 @@ /* Exynos5433 specific register definitions */ #define EXYNOS5433_USBHOST30_PHY_CONTROL (0x728) +#define EXYNOS5433_MIPI_PHY0_CONTROL (0x710) +#define EXYNOS5433_MIPI_PHY1_CONTROL (0x714) +#define EXYNOS5433_MIPI_PHY2_CONTROL (0x718) #define EXYNOS5_PHY_ENABLE BIT(0) -- cgit v1.2.3