Merge tag 'u-boot-imx-20200825' of https://gitlab.denx.de/u-boot/custodians/u-boot-imx
[platform/kernel/u-boot.git] / drivers / pinctrl / mvebu / pinctrl-mvebu.c
index d4f2970..146f5c6 100644 (file)
@@ -9,15 +9,57 @@
 #include <fdtdec.h>
 #include <errno.h>
 #include <dm.h>
+#include <log.h>
 #include <dm/pinctrl.h>
 #include <dm/root.h>
 #include <asm/system.h>
 #include <asm/io.h>
 #include <asm/arch-armada8k/soc-info.h>
+#include <linux/bitops.h>
 #include "pinctrl-mvebu.h"
 
+#define AP_EMMC_PHY_CTRL_REG           0x100
+#define CP_EMMC_PHY_CTRL_REG           0x424
+#define EMMC_PHY_CTRL_SDPHY_EN         BIT(0)
+
+#define AP806_EMMC_CLK_PIN_ID          0
+#define AP806_EMMC_CLK_FUNC            0x1
+#define CP110_EMMC_CLK_PIN_ID          56
+#define CP110_EMMC_CLK_FUNC            0xe
+
 DECLARE_GLOBAL_DATA_PTR;
 
+/* mvebu_pinctl_emmc_set_mux: configure sd/mmc PHY mux
+ * To enable SDIO/eMMC in Armada-APN806/CP110, need to configure PHY mux.
+ * eMMC/SD PHY register responsible for muxing between MPPs and SD/eMMC
+ * controller:
+ * - Bit0 enabled SDIO/eMMC PHY is used as a MPP muxltiplexer,
+ * - Bit0 disabled SDIO/eMMC PHY is connected to SDIO/eMMC controller
+ * If pin function is set to eMMC/SD, then configure the eMMC/SD PHY
+ * muxltiplexer register to be on SDIO/eMMC controller
+ */
+void mvebu_pinctl_emmc_set_mux(struct udevice *dev, u32 pin, u32 func)
+{
+       const void *blob = gd->fdt_blob;
+       int node = dev_of_offset(dev);
+       struct mvebu_pinctrl_priv *priv = dev_get_priv(dev);
+
+       if (!fdt_node_check_compatible(blob, node, "marvell,ap806-pinctrl")) {
+               if ((pin == AP806_EMMC_CLK_PIN_ID) &&
+                   (func == AP806_EMMC_CLK_FUNC)) {
+                       clrbits_le32(priv->base_reg + AP_EMMC_PHY_CTRL_REG,
+                                    EMMC_PHY_CTRL_SDPHY_EN);
+               }
+       } else if (!fdt_node_check_compatible(blob, node,
+                                       "marvell,armada-8k-cpm-pinctrl")) {
+               if ((pin == CP110_EMMC_CLK_PIN_ID) &&
+                   (func == CP110_EMMC_CLK_FUNC)) {
+                       clrbits_le32(priv->base_reg + CP_EMMC_PHY_CTRL_REG,
+                                    EMMC_PHY_CTRL_SDPHY_EN);
+               }
+       }
+}
+
 /*
  * mvebu_pinctrl_set_state: configure pin functions.
  * @dev: the pinctrl device to be configured.
@@ -47,9 +89,16 @@ int mvebu_pinctrl_set_state(struct udevice *dev, struct udevice *config)
 
        function = fdtdec_get_int(blob, node, "marvell,function", 0xff);
 
+       /*
+        * Check if setup of PHY mux is needed for this pins group.
+        * Only the first pin id in array is tested, all the rest use the same
+        * pin function.
+        */
+       mvebu_pinctl_emmc_set_mux(dev, pin_arr[0], function);
+
        for (i = 0; i < pin_count; i++) {
-       int reg_offset;
-       int field_offset;
+               int reg_offset;
+               int field_offset;
                int pin = pin_arr[i];
 
                if (function > priv->max_func) {
@@ -96,6 +145,14 @@ static int mvebu_pinctrl_set_state_all(struct udevice *dev,
                return -EINVAL;
        }
 
+       /* Check if setup of PHY mux is needed for this pins group. */
+       if (priv->pin_cnt < CP110_EMMC_CLK_PIN_ID)
+               mvebu_pinctl_emmc_set_mux(dev, AP806_EMMC_CLK_PIN_ID,
+                                         func_arr[AP806_EMMC_CLK_PIN_ID]);
+       else
+               mvebu_pinctl_emmc_set_mux(dev, CP110_EMMC_CLK_PIN_ID,
+                                         func_arr[CP110_EMMC_CLK_PIN_ID]);
+
        for (pin = 0; pin < priv->pin_cnt; pin++) {
                int reg_offset;
                int field_offset;
@@ -136,8 +193,8 @@ int mvebu_pinctl_probe(struct udevice *dev)
                return -EINVAL;
        }
 
-       priv->base_reg = devfdt_get_addr_ptr(dev);
-       if (priv->base_reg == (void *)FDT_ADDR_T_NONE) {
+       priv->base_reg = dev_read_addr_ptr(dev);
+       if (!priv->base_reg) {
                debug("%s: Failed to get base address\n", __func__);
                return -EINVAL;
        }
@@ -161,10 +218,10 @@ static struct pinctrl_ops mvebu_pinctrl_ops = {
 
 static const struct udevice_id mvebu_pinctrl_ids[] = {
        { .compatible = "marvell,mvebu-pinctrl" },
-       { .compatible = "marvell,armada-ap806-pinctrl" },
-       { .compatible = "marvell,a70x0-pinctrl" },
-       { .compatible = "marvell,a80x0-cp0-pinctrl" },
-       { .compatible = "marvell,a80x0-cp1-pinctrl" },
+       { .compatible = "marvell,ap806-pinctrl" },
+       { .compatible = "marvell,armada-7k-pinctrl" },
+       { .compatible = "marvell,armada-8k-cpm-pinctrl" },
+       { .compatible = "marvell,armada-8k-cps-pinctrl" },
        { }
 };