1 // SPDX-License-Identifier: GPL-2.0+ 2 /* 3 * Copyright (c) 2018 Emlid Limited 4 */ 5 6 #include <common.h> 7 #include <dm.h> 8 #include <dm/pinctrl.h> 9 #include <dm/read.h> 10 #include <regmap.h> 11 #include <syscon.h> 12 #include <asm/cpu.h> 13 #include <asm/scu.h> 14 #include <linux/io.h> 15 16 #define BUFCFG_OFFSET 0x100 17 18 #define MRFLD_FAMILY_LEN 0x400 19 20 /* These are taken from Linux kernel */ 21 #define MRFLD_PINMODE_MASK 0x07 22 23 #define pin_to_bufno(f, p) ((p) - (f)->pin_base) 24 25 struct mrfld_family { 26 unsigned int family_number; 27 unsigned int pin_base; 28 size_t npins; 29 void __iomem *regs; 30 }; 31 32 #define MRFLD_FAMILY(b, s, e) \ 33 { \ 34 .family_number = (b), \ 35 .pin_base = (s), \ 36 .npins = (e) - (s) + 1, \ 37 } 38 39 /* Now we only support I2C family of pins */ 40 static struct mrfld_family mrfld_families[] = { 41 MRFLD_FAMILY(7, 101, 114), 42 }; 43 44 struct mrfld_pinctrl { 45 const struct mrfld_family *families; 46 size_t nfamilies; 47 }; 48 49 static const struct mrfld_family * 50 mrfld_get_family(struct mrfld_pinctrl *mp, unsigned int pin) 51 { 52 const struct mrfld_family *family; 53 unsigned int i; 54 55 for (i = 0; i < mp->nfamilies; i++) { 56 family = &mp->families[i]; 57 if (pin >= family->pin_base && 58 pin < family->pin_base + family->npins) 59 return family; 60 } 61 62 pr_err("failed to find family for pin %u\n", pin); 63 return NULL; 64 } 65 66 static void __iomem * 67 mrfld_get_bufcfg(struct mrfld_pinctrl *pinctrl, unsigned int pin) 68 { 69 const struct mrfld_family *family; 70 unsigned int bufno; 71 72 family = mrfld_get_family(pinctrl, pin); 73 if (!family) 74 return NULL; 75 76 bufno = pin_to_bufno(family, pin); 77 78 return family->regs + BUFCFG_OFFSET + bufno * 4; 79 } 80 81 static void 82 mrfld_setup_families(void *base_addr, 83 struct mrfld_family *families, unsigned int nfam) 84 { 85 for (int i = 0; i < nfam; i++) { 86 struct mrfld_family *family = &families[i]; 87 88 family->regs = base_addr + 89 family->family_number * MRFLD_FAMILY_LEN; 90 } 91 } 92 93 static int mrfld_pinconfig_protected(unsigned int pin, u32 mask, u32 bits) 94 { 95 struct mrfld_pinctrl *pinctrl; 96 struct udevice *dev; 97 void __iomem *bufcfg; 98 u32 v, value; 99 int ret; 100 101 ret = syscon_get_by_driver_data(X86_SYSCON_PINCONF, &dev); 102 if (ret) 103 return ret; 104 105 pinctrl = dev_get_priv(dev); 106 107 bufcfg = mrfld_get_bufcfg(pinctrl, pin); 108 if (!bufcfg) 109 return -EINVAL; 110 111 value = readl(bufcfg); 112 113 v = (value & ~mask) | (bits & mask); 114 115 debug("scu: v: 0x%x p: 0x%x bits: %d, mask: %d bufcfg: 0x%p\n", 116 v, (u32)bufcfg, bits, mask, bufcfg); 117 118 ret = scu_ipc_raw_command(IPCMSG_INDIRECT_WRITE, 0, &v, 4, 119 NULL, 0, (u32)bufcfg, 0); 120 if (ret) 121 pr_err("Failed to set mode via SCU for pin %u (%d)\n", 122 pin, ret); 123 124 return ret; 125 } 126 127 static int mrfld_pinctrl_cfg_pin(ofnode pin_node) 128 { 129 bool is_protected; 130 int pad_offset; 131 int mode; 132 u32 mask; 133 int ret; 134 135 /* For now we only support just protected Family of pins */ 136 is_protected = ofnode_read_bool(pin_node, "protected"); 137 if (!is_protected) 138 return -ENOTSUPP; 139 140 pad_offset = ofnode_read_s32_default(pin_node, "pad-offset", -1); 141 if (pad_offset == -1) 142 return -EINVAL; 143 144 mode = ofnode_read_s32_default(pin_node, "mode-func", -1); 145 if (mode == -1) 146 return -EINVAL; 147 148 mask = MRFLD_PINMODE_MASK; 149 150 /* We don't support modes not in range 0..7 */ 151 if (mode & ~mask) 152 return -ENOTSUPP; 153 154 ret = mrfld_pinconfig_protected(pad_offset, mask, mode); 155 156 return ret; 157 } 158 159 static int tangier_pinctrl_probe(struct udevice *dev) 160 { 161 void *base_addr = syscon_get_first_range(X86_SYSCON_PINCONF); 162 struct mrfld_pinctrl *pinctrl = dev_get_priv(dev); 163 ofnode pin_node; 164 int ret; 165 166 mrfld_setup_families(base_addr, mrfld_families, 167 ARRAY_SIZE(mrfld_families)); 168 169 pinctrl->families = mrfld_families; 170 pinctrl->nfamilies = ARRAY_SIZE(mrfld_families); 171 172 ofnode_for_each_subnode(pin_node, dev_ofnode(dev)) { 173 ret = mrfld_pinctrl_cfg_pin(pin_node); 174 if (ret) { 175 pr_err("%s: invalid configuration for the pin %ld\n", 176 __func__, pin_node.of_offset); 177 } 178 } 179 180 return 0; 181 } 182 183 static const struct udevice_id tangier_pinctrl_match[] = { 184 { .compatible = "intel,pinctrl-tangier", .data = X86_SYSCON_PINCONF }, 185 { /* sentinel */ } 186 }; 187 188 U_BOOT_DRIVER(tangier_pinctrl) = { 189 .name = "tangier_pinctrl", 190 .id = UCLASS_SYSCON, 191 .of_match = tangier_pinctrl_match, 192 .probe = tangier_pinctrl_probe, 193 .priv_auto_alloc_size = sizeof(struct mrfld_pinctrl), 194 }; 195