1 // SPDX-License-Identifier: GPL-2.0-or-later 2 /* 3 * Marvell 88E6xxx Switch Global 2 Scratch & Misc Registers support 4 * 5 * Copyright (c) 2008 Marvell Semiconductor 6 * 7 * Copyright (c) 2017 National Instruments 8 * Brandon Streiff <brandon.streiff@ni.com> 9 */ 10 11 #include "chip.h" 12 #include "global2.h" 13 14 /* Offset 0x1A: Scratch and Misc. Register */ 15 static int mv88e6xxx_g2_scratch_read(struct mv88e6xxx_chip *chip, int reg, 16 u8 *data) 17 { 18 u16 value; 19 int err; 20 21 err = mv88e6xxx_g2_write(chip, MV88E6XXX_G2_SCRATCH_MISC_MISC, 22 reg << 8); 23 if (err) 24 return err; 25 26 err = mv88e6xxx_g2_read(chip, MV88E6XXX_G2_SCRATCH_MISC_MISC, &value); 27 if (err) 28 return err; 29 30 *data = (value & MV88E6XXX_G2_SCRATCH_MISC_DATA_MASK); 31 32 return 0; 33 } 34 35 static int mv88e6xxx_g2_scratch_write(struct mv88e6xxx_chip *chip, int reg, 36 u8 data) 37 { 38 u16 value = (reg << 8) | data; 39 40 return mv88e6xxx_g2_write(chip, MV88E6XXX_G2_SCRATCH_MISC_MISC, 41 MV88E6XXX_G2_SCRATCH_MISC_UPDATE | value); 42 } 43 44 /** 45 * mv88e6xxx_g2_scratch_get_bit - get a bit 46 * @chip: chip private data 47 * @base_reg: base of scratch bits 48 * @offset: index of bit within the register 49 * @set: is bit set? 50 */ 51 static int mv88e6xxx_g2_scratch_get_bit(struct mv88e6xxx_chip *chip, 52 int base_reg, unsigned int offset, 53 int *set) 54 { 55 int reg = base_reg + (offset / 8); 56 u8 mask = (1 << (offset & 0x7)); 57 u8 val; 58 int err; 59 60 err = mv88e6xxx_g2_scratch_read(chip, reg, &val); 61 if (err) 62 return err; 63 64 *set = !!(mask & val); 65 66 return 0; 67 } 68 69 /** 70 * mv88e6xxx_g2_scratch_set_bit - set (or clear) a bit 71 * @chip: chip private data 72 * @base_reg: base of scratch bits 73 * @offset: index of bit within the register 74 * @set: should this bit be set? 75 * 76 * Helper function for dealing with the direction and data registers. 77 */ 78 static int mv88e6xxx_g2_scratch_set_bit(struct mv88e6xxx_chip *chip, 79 int base_reg, unsigned int offset, 80 int set) 81 { 82 int reg = base_reg + (offset / 8); 83 u8 mask = (1 << (offset & 0x7)); 84 u8 val; 85 int err; 86 87 err = mv88e6xxx_g2_scratch_read(chip, reg, &val); 88 if (err) 89 return err; 90 91 if (set) 92 val |= mask; 93 else 94 val &= ~mask; 95 96 return mv88e6xxx_g2_scratch_write(chip, reg, val); 97 } 98 99 /** 100 * mv88e6352_g2_scratch_gpio_get_data - get data on gpio pin 101 * @chip: chip private data 102 * @pin: gpio index 103 * 104 * Return: 0 for low, 1 for high, negative error 105 */ 106 static int mv88e6352_g2_scratch_gpio_get_data(struct mv88e6xxx_chip *chip, 107 unsigned int pin) 108 { 109 int val = 0; 110 int err; 111 112 err = mv88e6xxx_g2_scratch_get_bit(chip, 113 MV88E6352_G2_SCRATCH_GPIO_DATA0, 114 pin, &val); 115 if (err) 116 return err; 117 118 return val; 119 } 120 121 /** 122 * mv88e6352_g2_scratch_gpio_set_data - set data on gpio pin 123 * @chip: chip private data 124 * @pin: gpio index 125 * @value: value to set 126 */ 127 static int mv88e6352_g2_scratch_gpio_set_data(struct mv88e6xxx_chip *chip, 128 unsigned int pin, int value) 129 { 130 u8 mask = (1 << (pin & 0x7)); 131 int offset = (pin / 8); 132 int reg; 133 134 reg = MV88E6352_G2_SCRATCH_GPIO_DATA0 + offset; 135 136 if (value) 137 chip->gpio_data[offset] |= mask; 138 else 139 chip->gpio_data[offset] &= ~mask; 140 141 return mv88e6xxx_g2_scratch_write(chip, reg, chip->gpio_data[offset]); 142 } 143 144 /** 145 * mv88e6352_g2_scratch_gpio_get_dir - get direction of gpio pin 146 * @chip: chip private data 147 * @pin: gpio index 148 * 149 * Return: 0 for output, 1 for input. 150 */ 151 static int mv88e6352_g2_scratch_gpio_get_dir(struct mv88e6xxx_chip *chip, 152 unsigned int pin) 153 { 154 int val = 0; 155 int err; 156 157 err = mv88e6xxx_g2_scratch_get_bit(chip, 158 MV88E6352_G2_SCRATCH_GPIO_DIR0, 159 pin, &val); 160 if (err) 161 return err; 162 163 return val; 164 } 165 166 /** 167 * mv88e6352_g2_scratch_gpio_set_dir - set direction of gpio pin 168 * @chip: chip private data 169 * @pin: gpio index 170 * @input: should the gpio be an input, or an output? 171 */ 172 static int mv88e6352_g2_scratch_gpio_set_dir(struct mv88e6xxx_chip *chip, 173 unsigned int pin, bool input) 174 { 175 int value = (input ? MV88E6352_G2_SCRATCH_GPIO_DIR_IN : 176 MV88E6352_G2_SCRATCH_GPIO_DIR_OUT); 177 178 return mv88e6xxx_g2_scratch_set_bit(chip, 179 MV88E6352_G2_SCRATCH_GPIO_DIR0, 180 pin, value); 181 } 182 183 /** 184 * mv88e6352_g2_scratch_gpio_get_pctl - get pin control setting 185 * @chip: chip private data 186 * @pin: gpio index 187 * @func: function number 188 * 189 * Note that the function numbers themselves may vary by chipset. 190 */ 191 static int mv88e6352_g2_scratch_gpio_get_pctl(struct mv88e6xxx_chip *chip, 192 unsigned int pin, int *func) 193 { 194 int reg = MV88E6352_G2_SCRATCH_GPIO_PCTL0 + (pin / 2); 195 int offset = (pin & 0x1) ? 4 : 0; 196 u8 mask = (0x7 << offset); 197 int err; 198 u8 val; 199 200 err = mv88e6xxx_g2_scratch_read(chip, reg, &val); 201 if (err) 202 return err; 203 204 *func = (val & mask) >> offset; 205 206 return 0; 207 } 208 209 /** 210 * mv88e6352_g2_scratch_gpio_set_pctl - set pin control setting 211 * @chip: chip private data 212 * @pin: gpio index 213 * @func: function number 214 */ 215 static int mv88e6352_g2_scratch_gpio_set_pctl(struct mv88e6xxx_chip *chip, 216 unsigned int pin, int func) 217 { 218 int reg = MV88E6352_G2_SCRATCH_GPIO_PCTL0 + (pin / 2); 219 int offset = (pin & 0x1) ? 4 : 0; 220 u8 mask = (0x7 << offset); 221 int err; 222 u8 val; 223 224 err = mv88e6xxx_g2_scratch_read(chip, reg, &val); 225 if (err) 226 return err; 227 228 val = (val & ~mask) | ((func & mask) << offset); 229 230 return mv88e6xxx_g2_scratch_write(chip, reg, val); 231 } 232 233 const struct mv88e6xxx_gpio_ops mv88e6352_gpio_ops = { 234 .get_data = mv88e6352_g2_scratch_gpio_get_data, 235 .set_data = mv88e6352_g2_scratch_gpio_set_data, 236 .get_dir = mv88e6352_g2_scratch_gpio_get_dir, 237 .set_dir = mv88e6352_g2_scratch_gpio_set_dir, 238 .get_pctl = mv88e6352_g2_scratch_gpio_get_pctl, 239 .set_pctl = mv88e6352_g2_scratch_gpio_set_pctl, 240 }; 241 242 /** 243 * mv88e6390_g2_scratch_gpio_set_smi - set gpio muxing for external smi 244 * @chip: chip private data 245 * @external: set mux for external smi, or free for gpio usage 246 * 247 * Some mv88e6xxx models have GPIO pins that may be configured as 248 * an external SMI interface, or they may be made free for other 249 * GPIO uses. 250 */ 251 int mv88e6390_g2_scratch_gpio_set_smi(struct mv88e6xxx_chip *chip, 252 bool external) 253 { 254 int misc_cfg = MV88E6352_G2_SCRATCH_MISC_CFG; 255 int config_data1 = MV88E6352_G2_SCRATCH_CONFIG_DATA1; 256 int config_data2 = MV88E6352_G2_SCRATCH_CONFIG_DATA2; 257 bool no_cpu; 258 u8 p0_mode; 259 int err; 260 u8 val; 261 262 err = mv88e6xxx_g2_scratch_read(chip, config_data2, &val); 263 if (err) 264 return err; 265 266 p0_mode = val & MV88E6352_G2_SCRATCH_CONFIG_DATA2_P0_MODE_MASK; 267 268 if (p0_mode == 0x01 || p0_mode == 0x02) 269 return -EBUSY; 270 271 err = mv88e6xxx_g2_scratch_read(chip, config_data1, &val); 272 if (err) 273 return err; 274 275 no_cpu = !!(val & MV88E6352_G2_SCRATCH_CONFIG_DATA1_NO_CPU); 276 277 err = mv88e6xxx_g2_scratch_read(chip, misc_cfg, &val); 278 if (err) 279 return err; 280 281 /* NO_CPU being 0 inverts the meaning of the bit */ 282 if (!no_cpu) 283 external = !external; 284 285 if (external) 286 val |= MV88E6352_G2_SCRATCH_MISC_CFG_NORMALSMI; 287 else 288 val &= ~MV88E6352_G2_SCRATCH_MISC_CFG_NORMALSMI; 289 290 return mv88e6xxx_g2_scratch_write(chip, misc_cfg, val); 291 } 292 293 /** 294 * mv88e6393x_g2_scratch_gpio_set_smi - set gpio muxing for external smi 295 * @chip: chip private data 296 * @external: set mux for external smi, or free for gpio usage 297 * 298 * MV88E6191X/6193X/6393X GPIO pins 9 and 10 can be configured as an 299 * external SMI interface or as regular GPIO-s. 300 * 301 * They however have a different register layout then the existing 302 * function. 303 */ 304 305 int mv88e6393x_g2_scratch_gpio_set_smi(struct mv88e6xxx_chip *chip, 306 bool external) 307 { 308 int misc_cfg = MV88E6352_G2_SCRATCH_MISC_CFG; 309 int err; 310 u8 val; 311 312 err = mv88e6xxx_g2_scratch_read(chip, misc_cfg, &val); 313 if (err) 314 return err; 315 316 if (external) 317 val &= ~MV88E6352_G2_SCRATCH_MISC_CFG_NORMALSMI; 318 else 319 val |= MV88E6352_G2_SCRATCH_MISC_CFG_NORMALSMI; 320 321 return mv88e6xxx_g2_scratch_write(chip, misc_cfg, val); 322 } 323 324 /** 325 * mv88e6352_g2_scratch_port_has_serdes - indicate if a port can have a serdes 326 * @chip: chip private data 327 * @port: port number to check for serdes 328 * 329 * Indicates whether the port may have a serdes attached according to the 330 * pin strapping. Returns negative error number, 0 if the port is not 331 * configured to have a serdes, and 1 if the port is configured to have a 332 * serdes attached. 333 */ 334 int mv88e6352_g2_scratch_port_has_serdes(struct mv88e6xxx_chip *chip, int port) 335 { 336 u8 config3, p; 337 int err; 338 339 err = mv88e6xxx_g2_scratch_read(chip, MV88E6352_G2_SCRATCH_CONFIG_DATA3, 340 &config3); 341 if (err) 342 return err; 343 344 if (config3 & MV88E6352_G2_SCRATCH_CONFIG_DATA3_S_SEL) 345 p = 5; 346 else 347 p = 4; 348 349 return port == p; 350 } 351