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