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