uboot/drivers/pinctrl/uniphier/pinctrl-uniphier-core.c
<<
>>
Prefs
   1/*
   2 * Copyright (C) 2015-2016 Socionext Inc.
   3 *   Author: Masahiro Yamada <yamada.masahiro@socionext.com>
   4 *
   5 * SPDX-License-Identifier:     GPL-2.0+
   6 */
   7
   8#include <linux/io.h>
   9#include <linux/err.h>
  10#include <linux/sizes.h>
  11#include <dm/device.h>
  12#include <dm/pinctrl.h>
  13
  14#include "pinctrl-uniphier.h"
  15
  16static const char *uniphier_pinctrl_dummy_name = "_dummy";
  17
  18static int uniphier_pinctrl_get_groups_count(struct udevice *dev)
  19{
  20        struct uniphier_pinctrl_priv *priv = dev_get_priv(dev);
  21
  22        return priv->socdata->groups_count;
  23}
  24
  25static const char *uniphier_pinctrl_get_group_name(struct udevice *dev,
  26                                                   unsigned selector)
  27{
  28        struct uniphier_pinctrl_priv *priv = dev_get_priv(dev);
  29
  30        if (!priv->socdata->groups[selector].name)
  31                return uniphier_pinctrl_dummy_name;
  32
  33        return priv->socdata->groups[selector].name;
  34}
  35
  36static int uniphier_pinmux_get_functions_count(struct udevice *dev)
  37{
  38        struct uniphier_pinctrl_priv *priv = dev_get_priv(dev);
  39
  40        return priv->socdata->functions_count;
  41}
  42
  43static const char *uniphier_pinmux_get_function_name(struct udevice *dev,
  44                                                     unsigned selector)
  45{
  46        struct uniphier_pinctrl_priv *priv = dev_get_priv(dev);
  47
  48        if (!priv->socdata->functions[selector])
  49                return uniphier_pinctrl_dummy_name;
  50
  51        return priv->socdata->functions[selector];
  52}
  53
  54static void uniphier_pinconf_input_enable_perpin(struct udevice *dev,
  55                                                 unsigned pin)
  56{
  57        struct uniphier_pinctrl_priv *priv = dev_get_priv(dev);
  58        unsigned reg;
  59        u32 mask, tmp;
  60
  61        reg = UNIPHIER_PINCTRL_IECTRL + pin / 32 * 4;
  62        mask = BIT(pin % 32);
  63
  64        tmp = readl(priv->base + reg);
  65        tmp |= mask;
  66        writel(tmp, priv->base + reg);
  67}
  68
  69static void uniphier_pinconf_input_enable_legacy(struct udevice *dev,
  70                                                 unsigned pin)
  71{
  72        struct uniphier_pinctrl_priv *priv = dev_get_priv(dev);
  73        int pins_count = priv->socdata->pins_count;
  74        const struct uniphier_pinctrl_pin *pins = priv->socdata->pins;
  75        int i;
  76
  77        for (i = 0; i < pins_count; i++) {
  78                if (pins[i].number == pin) {
  79                        unsigned int iectrl;
  80                        u32 tmp;
  81
  82                        iectrl = uniphier_pin_get_iectrl(pins[i].data);
  83                        tmp = readl(priv->base + UNIPHIER_PINCTRL_IECTRL);
  84                        tmp |= 1 << iectrl;
  85                        writel(tmp, priv->base + UNIPHIER_PINCTRL_IECTRL);
  86                }
  87        }
  88}
  89
  90static void uniphier_pinconf_input_enable(struct udevice *dev, unsigned pin)
  91{
  92        struct uniphier_pinctrl_priv *priv = dev_get_priv(dev);
  93
  94        if (priv->socdata->caps & UNIPHIER_PINCTRL_CAPS_PERPIN_IECTRL)
  95                uniphier_pinconf_input_enable_perpin(dev, pin);
  96        else
  97                uniphier_pinconf_input_enable_legacy(dev, pin);
  98}
  99
 100static void uniphier_pinmux_set_one(struct udevice *dev, unsigned pin,
 101                                    int muxval)
 102{
 103        struct uniphier_pinctrl_priv *priv = dev_get_priv(dev);
 104        unsigned mux_bits, reg_stride, reg, reg_end, shift, mask;
 105        bool load_pinctrl;
 106        u32 tmp;
 107
 108        /* some pins need input-enabling */
 109        uniphier_pinconf_input_enable(dev, pin);
 110
 111        if (muxval < 0)
 112                return;         /* dedicated pin; nothing to do for pin-mux */
 113
 114        if (priv->socdata->caps & UNIPHIER_PINCTRL_CAPS_DBGMUX_SEPARATE) {
 115                /*
 116                 *  Mode       offset        bit
 117                 *  Normal     4 * n     shift+3:shift
 118                 *  Debug      4 * n     shift+7:shift+4
 119                 */
 120                mux_bits = 4;
 121                reg_stride = 8;
 122                load_pinctrl = true;
 123        } else {
 124                /*
 125                 *  Mode       offset           bit
 126                 *  Normal     8 * n        shift+3:shift
 127                 *  Debug      8 * n + 4    shift+3:shift
 128                 */
 129                mux_bits = 8;
 130                reg_stride = 4;
 131                load_pinctrl = false;
 132        }
 133
 134        reg = UNIPHIER_PINCTRL_PINMUX_BASE + pin * mux_bits / 32 * reg_stride;
 135        reg_end = reg + reg_stride;
 136        shift = pin * mux_bits % 32;
 137        mask = (1U << mux_bits) - 1;
 138
 139        /*
 140         * If reg_stride is greater than 4, the MSB of each pinsel shall be
 141         * stored in the offset+4.
 142         */
 143        for (; reg < reg_end; reg += 4) {
 144                tmp = readl(priv->base + reg);
 145                tmp &= ~(mask << shift);
 146                tmp |= (mask & muxval) << shift;
 147                writel(tmp, priv->base + reg);
 148
 149                muxval >>= mux_bits;
 150        }
 151
 152        if (load_pinctrl)
 153                writel(1, priv->base + UNIPHIER_PINCTRL_LOAD_PINMUX);
 154}
 155
 156static int uniphier_pinmux_group_set(struct udevice *dev,
 157                                     unsigned group_selector,
 158                                     unsigned func_selector)
 159{
 160        struct uniphier_pinctrl_priv *priv = dev_get_priv(dev);
 161        const struct uniphier_pinctrl_group *grp =
 162                                        &priv->socdata->groups[group_selector];
 163        int i;
 164
 165        for (i = 0; i < grp->num_pins; i++)
 166                uniphier_pinmux_set_one(dev, grp->pins[i], grp->muxvals[i]);
 167
 168        return 0;
 169}
 170
 171const struct pinctrl_ops uniphier_pinctrl_ops = {
 172        .get_groups_count = uniphier_pinctrl_get_groups_count,
 173        .get_group_name = uniphier_pinctrl_get_group_name,
 174        .get_functions_count = uniphier_pinmux_get_functions_count,
 175        .get_function_name = uniphier_pinmux_get_function_name,
 176        .pinmux_group_set = uniphier_pinmux_group_set,
 177        .set_state = pinctrl_generic_set_state,
 178};
 179
 180int uniphier_pinctrl_probe(struct udevice *dev,
 181                           struct uniphier_pinctrl_socdata *socdata)
 182{
 183        struct uniphier_pinctrl_priv *priv = dev_get_priv(dev);
 184        fdt_addr_t addr;
 185
 186        addr = dev_get_addr(dev->parent);
 187        if (addr == FDT_ADDR_T_NONE)
 188                return -EINVAL;
 189
 190        priv->base = devm_ioremap(dev, addr, SZ_4K);
 191        if (!priv->base)
 192                return -ENOMEM;
 193
 194        priv->socdata = socdata;
 195
 196        return 0;
 197}
 198