]> git.karo-electronics.de Git - karo-tx-linux.git/commitdiff
Merge tag 'phy-for-4.7' of git://git.kernel.org/pub/scm/linux/kernel/git/kishon/linux...
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Tue, 3 May 2016 21:49:46 +0000 (14:49 -0700)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Tue, 3 May 2016 21:49:46 +0000 (14:49 -0700)
Kishon writes:

phy: for 4.7

*) Add a new PHY driver for USB2 PHY on Northstar SoC
*) Add support for Broadcom NS2 SATA3 PHY in existing
   Broadcom SATA3 PHY driver
*) Add support for MIPI DPHYs in Exynos5420-compatible
   (5420, 5422 and 5800) and Exynos5433 SoCs
*) Add support for USB3 PHY on mt2701
*) Add extcon support for Renesas R-car USB2 PHY driver
*) Misc cleanups

Signed-off-by: Kishon Vijay Abraham I <kishon@ti.com>
19 files changed:
Documentation/devicetree/bindings/phy/bcm-ns-usb2-phy.txt [new file with mode: 0644]
Documentation/devicetree/bindings/phy/brcm-sata-phy.txt [moved from Documentation/devicetree/bindings/phy/brcm,brcmstb-sata-phy.txt with 69% similarity]
Documentation/devicetree/bindings/phy/phy-mt65xx-usb.txt
Documentation/devicetree/bindings/phy/rcar-gen2-phy.txt
Documentation/devicetree/bindings/phy/rcar-gen3-phy-usb2.txt
Documentation/devicetree/bindings/phy/samsung-phy.txt
drivers/phy/Kconfig
drivers/phy/Makefile
drivers/phy/phy-bcm-ns-usb2.c [new file with mode: 0644]
drivers/phy/phy-brcm-sata.c [new file with mode: 0644]
drivers/phy/phy-brcmstb-sata.c [deleted file]
drivers/phy/phy-exynos-mipi-video.c
drivers/phy/phy-mt65xx-usb3.c
drivers/phy/phy-rcar-gen2.c
drivers/phy/phy-rcar-gen3-usb2.c
drivers/phy/phy-rockchip-usb.c
include/linux/bcma/bcma.h
include/linux/bcma/bcma_driver_arm_c9.h [new file with mode: 0644]
include/linux/mfd/syscon/exynos5-pmu.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 (file)
index 0000000..a7aee9e
--- /dev/null
@@ -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";
+       };
similarity index 69%
rename from Documentation/devicetree/bindings/phy/brcm,brcmstb-sata-phy.txt
rename to Documentation/devicetree/bindings/phy/brcm-sata-phy.txt
index d87ab7c127b8a0c439feee9d181ba1fd8f32283a..d0231209d8466aab35fb2fc1ac0dad7d6b02caad 100644 (file)
@@ -1,14 +1,17 @@
-* Broadcom SATA3 PHY for STB
+* 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 range for the PHY PCB interface
-- reg-names: should be "phy"
+- 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.
@@ -16,12 +19,12 @@ Sub-nodes:
 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
 
+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>;
index 00100cf3e037aa7f7bceb932518550769010b78a..33a2b1ee3f3eb20e09c8cefe400292468b3f6e43 100644 (file)
@@ -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
index d564ba4f1cf680643522732cfef906428feb6045..91da947ae9b6205fa4cf6fb233e5218abb62b1d0 100644 (file)
@@ -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>;
index eaf7e9b7ce6bf687106b8b8828cf75d60bebfbd7..2281d6cdecb13cfec3c7c6c9ad6ab4a641524fa4 100644 (file)
@@ -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>.
@@ -15,18 +21,20 @@ 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):
 
        usb-phy@ee080200 {
-               compatible = "renesas,usb2-phy-r8a7795";
+               compatible = "renesas,usb2-phy-r8a7795", "renesas,rcar-gen3-usb2-phy";
                reg = <0 0xee080200 0 0x700>;
                interrupts = <GIC_SPI 108 IRQ_TYPE_LEVEL_HIGH>;
                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>;
        };
index 0289d3b07853e73f494106aca13780899a508abc..9872ba8546bda67c16cfe27beea7734d9c8baff4 100644 (file)
@@ -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
 -------------------------------------------------
index e92b97cd605693f33c77de2657e3abab89865d8e..a83ed81d8df870d6c69991ad8992baed89a3102a 100644 (file)
@@ -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
@@ -113,14 +122,15 @@ 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
+       depends on EXTCON
        select GENERIC_PHY
        help
          Support for USB 2.0 PHY found on Renesas R-Car generation 3 SoCs.
@@ -218,9 +228,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"
@@ -404,14 +413,15 @@ 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
+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 SATA3 PHY on 28nm or 40nm Broadcom STB SoCs.
-         Likely useful only with CONFIG_SATA_BRCMSTB enabled.
+         Enable this to support the Broadcom SATA PHY.
+         If unsure, say N.
 
 config PHY_CYGNUS_PCIE
        tristate "Broadcom Cygnus PCIe PHY driver"
index 24596a96a8876faa14ddf7a94175c55e1603628a..0de09e13fdbce42148f77780a3909e86f65b0331 100644 (file)
@@ -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
@@ -49,6 +50,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_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
diff --git a/drivers/phy/phy-bcm-ns-usb2.c b/drivers/phy/phy-bcm-ns-usb2.c
new file mode 100644 (file)
index 0000000..95ab6b2
--- /dev/null
@@ -0,0 +1,137 @@
+/*
+ * Broadcom Northstar USB 2.0 PHY Driver
+ *
+ * Copyright (C) 2016 RafaÅ‚ MiÅ‚ecki <zajec5@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#include <linux/bcma/bcma.h>
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/module.h>
+#include <linux/of_address.h>
+#include <linux/of_platform.h>
+#include <linux/phy/phy.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+
+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/drivers/phy/phy-brcm-sata.c b/drivers/phy/phy-brcm-sata.c
new file mode 100644 (file)
index 0000000..6c4c5cb
--- /dev/null
@@ -0,0 +1,412 @@
+/*
+ * 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 <linux/delay.h>
+#include <linux/device.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/phy/phy.h>
+#include <linux/platform_device.h>
+
+#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_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_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_STB_28NM,
+       BRCM_SATA_PHY_STB_40NM,
+       BRCM_SATA_PHY_IPROC_NS2,
+};
+
+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;
+       void __iomem *ctrl_base;
+       enum brcm_sata_phy_version version;
+
+       struct brcm_sata_port phys[MAX_PORTS];
+};
+
+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),
+       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,
+};
+
+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 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;
+       };
+
+       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->ctrl_base + (port->portnum * size);
+}
+
+static void brcm_sata_phy_wr(void __iomem *pcb_base, u32 bank,
+                            u32 ofs, u32 msk, u32 value)
+{
+       u32 tmp;
+
+       writel(bank, pcb_base + SATA_PCB_BANK_OFFSET);
+       tmp = readl(pcb_base + SATA_PCB_REG_OFFSET(ofs));
+       tmp = (tmp & msk) | value;
+       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 STB_FMIN_VAL_DEFAULT   0x3df
+#define STB_FMAX_VAL_DEFAULT   0x3df
+#define STB_FMAX_VAL_SSC       0x83
+
+static int brcm_stb_sata_init(struct brcm_sata_port *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_phy_wr(base, TXPMD_REG_BANK, TXPMD_CONTROL1, ~tmp, tmp);
+
+       /* set fixed min freq */
+       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 = STB_FMAX_VAL_SSC;
+       } else {
+               tmp = STB_FMAX_VAL_DEFAULT;
+       }
+
+       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);
+
+       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;
+}
+
+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_STB_28NM },
+       { .compatible   = "brcm,bcm7425-sata-phy",
+         .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);
+
+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_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;
+               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 (file)
index a23172f..0000000
+++ /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 <linux/device.h>
-#include <linux/init.h>
-#include <linux/interrupt.h>
-#include <linux/io.h>
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/of.h>
-#include <linux/phy/phy.h>
-#include <linux/platform_device.h>
-
-#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");
index 2a54caba93b4021a5b48c44100ec42e9baf45da4..cc093ebfda9435a28ec627ca1f022b877c42b342 100644 (file)
@@ -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 <s.nawrocki@samsung.com>
  *
  * This program is free software; you can redistribute it and/or modify
 #include <linux/io.h>
 #include <linux/kernel.h>
 #include <linux/mfd/syscon/exynos4-pmu.h>
+#include <linux/mfd/syscon/exynos5-pmu.h>
 #include <linux/module.h>
 #include <linux/of.h>
 #include <linux/of_address.h>
+#include <linux/of_device.h>
 #include <linux/phy/phy.h>
-#include <linux/platform_device.h>
 #include <linux/regmap.h>
 #include <linux/spinlock.h>
 #include <linux/mfd/syscon.h>
 
-/* 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_NONE = -1,
        EXYNOS_MIPI_PHY_ID_CSIS0,
        EXYNOS_MIPI_PHY_ID_DSIM0,
        EXYNOS_MIPI_PHY_ID_CSIS1,
        EXYNOS_MIPI_PHY_ID_DSIM1,
+       EXYNOS_MIPI_PHY_ID_CSIS2,
        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_REGMAP_DISP,
+       EXYNOS_MIPI_REGMAP_CAM0,
+       EXYNOS_MIPI_REGMAP_CAM1,
+       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,
+               },
+       },
+};
+
+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];
+       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);
-       void __iomem *addr;
-       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);
 
-       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);
+       /* 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)
@@ -110,7 +290,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,
@@ -118,7 +298,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;
@@ -132,32 +312,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)) {
-               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);
+       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)) {
@@ -167,6 +348,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]);
        }
 
@@ -177,8 +359,17 @@ 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,
+       }, {
+               .compatible = "samsung,exynos5420-mipi-video-phy",
+               .data = &exynos5420_mipi_phy,
+       }, {
+               .compatible = "samsung,exynos5433-mipi-video-phy",
+               .data = &exynos5433_mipi_phy,
+       },
+       { /* sentinel */ },
 };
 MODULE_DEVICE_TABLE(of, exynos_mipi_video_phy_of_match);
 
index c0e7b4b0cf5c66c942977c36b9d5f46ef97ca4e8..4d85e730ccab131dc0821423c5d73427b6f89097 100644 (file)
 #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         = {
index c7a05996d5c1a841a65e515e746d1008d3d47489..97d4dd6ea9247d8fc3ec36ce4021ed17af1d0ac3 100644 (file)
@@ -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);
index bc4f7dd821aa5a33f63106b23311fa7fceaaad41..76bb88f0700a72b8d06480daf4d8e2aa8b0b51de 100644 (file)
@@ -12,6 +12,7 @@
  * published by the Free Software Foundation.
  */
 
+#include <linux/extcon.h>
 #include <linux/interrupt.h>
 #include <linux/io.h>
 #include <linux/module.h>
@@ -19,6 +20,7 @@
 #include <linux/of_address.h>
 #include <linux/phy/phy.h>
 #include <linux/platform_device.h>
+#include <linux/regulator/consumer.h>
 
 /******* USB2.0 Host registers (original offset is +0x200) *******/
 #define USB2_INT_ENABLE                0x000
 #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 extcon_dev *extcon;
        struct phy *phy;
+       struct regulator *vbus;
        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 +99,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 +113,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);
@@ -130,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)
@@ -137,17 +139,20 @@ 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)
 {
-       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 +171,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 +192,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 +210,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,8 +218,15 @@ 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;
+       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;
@@ -225,17 +237,29 @@ 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,
 };
 
 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;
 
@@ -251,10 +275,17 @@ 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);
 
+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;
@@ -273,18 +304,30 @@ 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);
        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); */
@@ -294,6 +337,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);
index f62d899063a336a8e265f747d7a754744307c486..d60b149cff0fa7f44c28bea07d55579f9efc80d7 100644 (file)
@@ -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;
                }
index 0367c63f596019b5b94d66f315d426e6ab8a4cc4..e6b41f42602ba7cc32e2945e15309d06f3028f95 100644 (file)
@@ -4,6 +4,7 @@
 #include <linux/pci.h>
 #include <linux/mod_devicetable.h>
 
+#include <linux/bcma/bcma_driver_arm_c9.h>
 #include <linux/bcma/bcma_driver_chipcommon.h>
 #include <linux/bcma/bcma_driver_pci.h>
 #include <linux/bcma/bcma_driver_pcie2.h>
diff --git a/include/linux/bcma/bcma_driver_arm_c9.h b/include/linux/bcma/bcma_driver_arm_c9.h
new file mode 100644 (file)
index 0000000..93bd73d
--- /dev/null
@@ -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_ */
index 9352adc95de6f4115294db75ffac16e376e86f2a..76f30f940c701ba2beac6ecab8daab742e98df9a 100644 (file)
@@ -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)