1 /* 2 * Copyright (C) 2016 Marvell International Ltd. 3 * 4 * SPDX-License-Identifier: GPL-2.0 5 * https://spdx.org/licenses 6 */ 7 8 #include <common.h> 9 #include <config.h> 10 #include <fdtdec.h> 11 #include <errno.h> 12 #include <dm.h> 13 #include <dm/pinctrl.h> 14 #include <dm/root.h> 15 #include <asm/system.h> 16 #include <asm/io.h> 17 #include <asm/arch-armada8k/soc-info.h> 18 #include "pinctrl-mvebu.h" 19 20 DECLARE_GLOBAL_DATA_PTR; 21 22 /* 23 * mvebu_pinctrl_set_state: configure pin functions. 24 * @dev: the pinctrl device to be configured. 25 * @config: the state to be configured. 26 * @return: 0 in success 27 */ 28 int mvebu_pinctrl_set_state(struct udevice *dev, struct udevice *config) 29 { 30 const void *blob = gd->fdt_blob; 31 int node = config->of_offset; 32 struct mvebu_pinctrl_priv *priv; 33 u32 pin_arr[MVEBU_MAX_PINS_PER_BANK]; 34 u32 function; 35 int i, pin_count; 36 37 priv = dev_get_priv(dev); 38 39 pin_count = fdtdec_get_int_array_count(blob, node, 40 "marvell,pins", 41 pin_arr, 42 MVEBU_MAX_PINS_PER_BANK); 43 if (pin_count <= 0) { 44 debug("Failed reading pins array for pinconfig %s (%d)\n", 45 config->name, pin_count); 46 return -EINVAL; 47 } 48 49 function = fdtdec_get_int(blob, node, "marvell,function", 0xff); 50 51 for (i = 0; i < pin_count; i++) { 52 int reg_offset; 53 int field_offset; 54 int pin = pin_arr[i]; 55 56 if (function > priv->max_func) { 57 debug("Illegal function %d for pinconfig %s\n", 58 function, config->name); 59 return -EINVAL; 60 } 61 62 /* Calculate register address and bit in register */ 63 reg_offset = priv->reg_direction * 4 * 64 (pin >> (PIN_REG_SHIFT)); 65 field_offset = (BITS_PER_PIN) * (pin & PIN_FIELD_MASK); 66 67 clrsetbits_le32(priv->base_reg + reg_offset, 68 PIN_FUNC_MASK << field_offset, 69 (function & PIN_FUNC_MASK) << field_offset); 70 } 71 72 return 0; 73 } 74 75 /* 76 * mvebu_pinctrl_set_state_all: configure the entire bank pin functions. 77 * @dev: the pinctrl device to be configured. 78 * @config: the state to be configured. 79 * @return: 0 in success 80 */ 81 static int mvebu_pinctrl_set_state_all(struct udevice *dev, 82 struct udevice *config) 83 { 84 const void *blob = gd->fdt_blob; 85 int node = config->of_offset; 86 struct mvebu_pinctrl_priv *priv; 87 u32 func_arr[MVEBU_MAX_PINS_PER_BANK]; 88 int pin, err; 89 90 priv = dev_get_priv(dev); 91 92 err = fdtdec_get_int_array(blob, node, "pin-func", 93 func_arr, priv->pin_cnt); 94 if (err) { 95 debug("Failed reading pin functions for bank %s\n", 96 priv->bank_name); 97 return -EINVAL; 98 } 99 100 for (pin = 0; pin < priv->pin_cnt; pin++) { 101 int reg_offset; 102 int field_offset; 103 u32 func = func_arr[pin]; 104 105 /* Bypass pins with function 0xFF */ 106 if (func == 0xff) { 107 debug("Warning: pin %d value is not modified ", pin); 108 debug("(kept as default)\n"); 109 continue; 110 } else if (func > priv->max_func) { 111 debug("Illegal function %d for pin %d\n", func, pin); 112 return -EINVAL; 113 } 114 115 /* Calculate register address and bit in register */ 116 reg_offset = priv->reg_direction * 4 * 117 (pin >> (PIN_REG_SHIFT)); 118 field_offset = (BITS_PER_PIN) * (pin & PIN_FIELD_MASK); 119 120 clrsetbits_le32(priv->base_reg + reg_offset, 121 PIN_FUNC_MASK << field_offset, 122 (func & PIN_FUNC_MASK) << field_offset); 123 } 124 125 return 0; 126 } 127 128 int mvebu_pinctl_probe(struct udevice *dev) 129 { 130 const void *blob = gd->fdt_blob; 131 int node = dev->of_offset; 132 struct mvebu_pinctrl_priv *priv; 133 134 priv = dev_get_priv(dev); 135 if (!priv) { 136 debug("%s: Failed to get private\n", __func__); 137 return -EINVAL; 138 } 139 140 priv->base_reg = dev_get_addr_ptr(dev); 141 if (priv->base_reg == (void *)FDT_ADDR_T_NONE) { 142 debug("%s: Failed to get base address\n", __func__); 143 return -EINVAL; 144 } 145 146 priv->pin_cnt = fdtdec_get_int(blob, node, "pin-count", 147 MVEBU_MAX_PINS_PER_BANK); 148 priv->max_func = fdtdec_get_int(blob, node, "max-func", 149 MVEBU_MAX_FUNC); 150 priv->bank_name = fdt_getprop(blob, node, "bank-name", NULL); 151 152 priv->reg_direction = 1; 153 if (fdtdec_get_bool(blob, node, "reverse-reg")) 154 priv->reg_direction = -1; 155 156 return mvebu_pinctrl_set_state_all(dev, dev); 157 } 158 159 static struct pinctrl_ops mvebu_pinctrl_ops = { 160 .set_state = mvebu_pinctrl_set_state 161 }; 162 163 static const struct udevice_id mvebu_pinctrl_ids[] = { 164 { .compatible = "marvell,mvebu-pinctrl" }, 165 { .compatible = "marvell,armada-ap806-pinctrl" }, 166 { .compatible = "marvell,a70x0-pinctrl" }, 167 { .compatible = "marvell,a80x0-cp0-pinctrl" }, 168 { .compatible = "marvell,a80x0-cp1-pinctrl" }, 169 { } 170 }; 171 172 U_BOOT_DRIVER(pinctrl_mvebu) = { 173 .name = "mvebu_pinctrl", 174 .id = UCLASS_PINCTRL, 175 .of_match = mvebu_pinctrl_ids, 176 .priv_auto_alloc_size = sizeof(struct mvebu_pinctrl_priv), 177 .ops = &mvebu_pinctrl_ops, 178 .probe = mvebu_pinctl_probe 179 }; 180