uboot/drivers/pinctrl/mvebu/pinctrl-mvebu.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2/*
   3 * Copyright (C) 2016 Marvell International Ltd.
   4 * https://spdx.org/licenses
   5 */
   6
   7#include <common.h>
   8#include <config.h>
   9#include <fdtdec.h>
  10#include <errno.h>
  11#include <dm.h>
  12#include <log.h>
  13#include <asm/global_data.h>
  14#include <dm/pinctrl.h>
  15#include <dm/root.h>
  16#include <asm/system.h>
  17#include <asm/io.h>
  18#include <asm/arch-armada8k/soc-info.h>
  19#include <linux/bitops.h>
  20#include "pinctrl-mvebu.h"
  21
  22#define AP_EMMC_PHY_CTRL_REG            0x100
  23#define CP_EMMC_PHY_CTRL_REG            0x424
  24#define EMMC_PHY_CTRL_SDPHY_EN          BIT(0)
  25
  26#define AP806_EMMC_CLK_PIN_ID           0
  27#define AP806_EMMC_CLK_FUNC             0x1
  28#define CP110_EMMC_CLK_PIN_ID           56
  29#define CP110_EMMC_CLK_FUNC             0xe
  30
  31DECLARE_GLOBAL_DATA_PTR;
  32
  33/* mvebu_pinctl_emmc_set_mux: configure sd/mmc PHY mux
  34 * To enable SDIO/eMMC in Armada-APN806/CP110, need to configure PHY mux.
  35 * eMMC/SD PHY register responsible for muxing between MPPs and SD/eMMC
  36 * controller:
  37 * - Bit0 enabled SDIO/eMMC PHY is used as a MPP muxltiplexer,
  38 * - Bit0 disabled SDIO/eMMC PHY is connected to SDIO/eMMC controller
  39 * If pin function is set to eMMC/SD, then configure the eMMC/SD PHY
  40 * muxltiplexer register to be on SDIO/eMMC controller
  41 */
  42void mvebu_pinctl_emmc_set_mux(struct udevice *dev, u32 pin, u32 func)
  43{
  44        const void *blob = gd->fdt_blob;
  45        int node = dev_of_offset(dev);
  46        struct mvebu_pinctrl_priv *priv = dev_get_priv(dev);
  47
  48        if (!fdt_node_check_compatible(blob, node, "marvell,ap806-pinctrl")) {
  49                if ((pin == AP806_EMMC_CLK_PIN_ID) &&
  50                    (func == AP806_EMMC_CLK_FUNC)) {
  51                        clrbits_le32(priv->base_reg + AP_EMMC_PHY_CTRL_REG,
  52                                     EMMC_PHY_CTRL_SDPHY_EN);
  53                }
  54        } else if (!fdt_node_check_compatible(blob, node,
  55                                        "marvell,armada-8k-cpm-pinctrl")) {
  56                if ((pin == CP110_EMMC_CLK_PIN_ID) &&
  57                    (func == CP110_EMMC_CLK_FUNC)) {
  58                        clrbits_le32(priv->base_reg + CP_EMMC_PHY_CTRL_REG,
  59                                     EMMC_PHY_CTRL_SDPHY_EN);
  60                }
  61        }
  62}
  63
  64/*
  65 * mvebu_pinctrl_set_state: configure pin functions.
  66 * @dev: the pinctrl device to be configured.
  67 * @config: the state to be configured.
  68 * @return: 0 in success
  69 */
  70int mvebu_pinctrl_set_state(struct udevice *dev, struct udevice *config)
  71{
  72        const void *blob = gd->fdt_blob;
  73        int node = dev_of_offset(config);
  74        struct mvebu_pinctrl_priv *priv;
  75        u32 pin_arr[MVEBU_MAX_PINS_PER_BANK];
  76        u32 function;
  77        int i, pin_count;
  78
  79        priv = dev_get_priv(dev);
  80
  81        pin_count = fdtdec_get_int_array_count(blob, node,
  82                                               "marvell,pins",
  83                                               pin_arr,
  84                                               MVEBU_MAX_PINS_PER_BANK);
  85        if (pin_count <= 0) {
  86                debug("Failed reading pins array for pinconfig %s (%d)\n",
  87                      config->name, pin_count);
  88                return -EINVAL;
  89        }
  90
  91        function = fdtdec_get_int(blob, node, "marvell,function", 0xff);
  92
  93        /*
  94         * Check if setup of PHY mux is needed for this pins group.
  95         * Only the first pin id in array is tested, all the rest use the same
  96         * pin function.
  97         */
  98        mvebu_pinctl_emmc_set_mux(dev, pin_arr[0], function);
  99
 100        for (i = 0; i < pin_count; i++) {
 101                int reg_offset;
 102                int field_offset;
 103                int pin = pin_arr[i];
 104
 105                if (function > priv->max_func) {
 106                        debug("Illegal function %d for pinconfig %s\n",
 107                              function, config->name);
 108                        return -EINVAL;
 109                }
 110
 111                /* Calculate register address and bit in register */
 112                reg_offset   = priv->reg_direction * 4 *
 113                                        (pin >> (PIN_REG_SHIFT));
 114                field_offset = (BITS_PER_PIN) * (pin & PIN_FIELD_MASK);
 115
 116                clrsetbits_le32(priv->base_reg + reg_offset,
 117                                PIN_FUNC_MASK << field_offset,
 118                                (function & PIN_FUNC_MASK) << field_offset);
 119        }
 120
 121        return 0;
 122}
 123
 124/*
 125 * mvebu_pinctrl_set_state_all: configure the entire bank pin functions.
 126 * @dev: the pinctrl device to be configured.
 127 * @config: the state to be configured.
 128 * @return: 0 in success
 129 */
 130static int mvebu_pinctrl_set_state_all(struct udevice *dev,
 131                                       struct udevice *config)
 132{
 133        const void *blob = gd->fdt_blob;
 134        int node = dev_of_offset(config);
 135        struct mvebu_pinctrl_priv *priv;
 136        u32 func_arr[MVEBU_MAX_PINS_PER_BANK];
 137        int pin, err;
 138
 139        priv = dev_get_priv(dev);
 140
 141        err = fdtdec_get_int_array(blob, node, "pin-func",
 142                                   func_arr, priv->pin_cnt);
 143        if (err) {
 144                debug("Failed reading pin functions for bank %s\n",
 145                      priv->bank_name);
 146                return -EINVAL;
 147        }
 148
 149        /* Check if setup of PHY mux is needed for this pins group. */
 150        if (priv->pin_cnt < CP110_EMMC_CLK_PIN_ID)
 151                mvebu_pinctl_emmc_set_mux(dev, AP806_EMMC_CLK_PIN_ID,
 152                                          func_arr[AP806_EMMC_CLK_PIN_ID]);
 153        else
 154                mvebu_pinctl_emmc_set_mux(dev, CP110_EMMC_CLK_PIN_ID,
 155                                          func_arr[CP110_EMMC_CLK_PIN_ID]);
 156
 157        for (pin = 0; pin < priv->pin_cnt; pin++) {
 158                int reg_offset;
 159                int field_offset;
 160                u32 func = func_arr[pin];
 161
 162                /* Bypass pins with function 0xFF */
 163                if (func == 0xff) {
 164                        debug("Warning: pin %d value is not modified ", pin);
 165                        debug("(kept as default)\n");
 166                        continue;
 167                } else if (func > priv->max_func) {
 168                        debug("Illegal function %d for pin %d\n", func, pin);
 169                        return -EINVAL;
 170                }
 171
 172                /* Calculate register address and bit in register */
 173                reg_offset   = priv->reg_direction * 4 *
 174                                        (pin >> (PIN_REG_SHIFT));
 175                field_offset = (BITS_PER_PIN) * (pin & PIN_FIELD_MASK);
 176
 177                clrsetbits_le32(priv->base_reg + reg_offset,
 178                                PIN_FUNC_MASK << field_offset,
 179                                (func & PIN_FUNC_MASK) << field_offset);
 180        }
 181
 182        return 0;
 183}
 184
 185int mvebu_pinctl_probe(struct udevice *dev)
 186{
 187        const void *blob = gd->fdt_blob;
 188        int node = dev_of_offset(dev);
 189        struct mvebu_pinctrl_priv *priv;
 190
 191        priv = dev_get_priv(dev);
 192        if (!priv) {
 193                debug("%s: Failed to get private\n", __func__);
 194                return -EINVAL;
 195        }
 196
 197        priv->base_reg = dev_read_addr_ptr(dev);
 198        if (!priv->base_reg) {
 199                debug("%s: Failed to get base address\n", __func__);
 200                return -EINVAL;
 201        }
 202
 203        priv->pin_cnt   = fdtdec_get_int(blob, node, "pin-count",
 204                                        MVEBU_MAX_PINS_PER_BANK);
 205        priv->max_func  = fdtdec_get_int(blob, node, "max-func",
 206                                         MVEBU_MAX_FUNC);
 207        priv->bank_name = fdt_getprop(blob, node, "bank-name", NULL);
 208
 209        priv->reg_direction = 1;
 210        if (fdtdec_get_bool(blob, node, "reverse-reg"))
 211                priv->reg_direction = -1;
 212
 213        return mvebu_pinctrl_set_state_all(dev, dev);
 214}
 215
 216static struct pinctrl_ops mvebu_pinctrl_ops = {
 217        .set_state      = mvebu_pinctrl_set_state
 218};
 219
 220static const struct udevice_id mvebu_pinctrl_ids[] = {
 221        { .compatible = "marvell,mvebu-pinctrl" },
 222        { .compatible = "marvell,ap806-pinctrl" },
 223        { .compatible = "marvell,armada-7k-pinctrl" },
 224        { .compatible = "marvell,armada-8k-cpm-pinctrl" },
 225        { .compatible = "marvell,armada-8k-cps-pinctrl" },
 226        { }
 227};
 228
 229U_BOOT_DRIVER(pinctrl_mvebu) = {
 230        .name           = "mvebu_pinctrl",
 231        .id             = UCLASS_PINCTRL,
 232        .of_match       = mvebu_pinctrl_ids,
 233        .priv_auto      = sizeof(struct mvebu_pinctrl_priv),
 234        .ops            = &mvebu_pinctrl_ops,
 235        .probe          = mvebu_pinctl_probe
 236};
 237