12874c5fdSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later 2a73ccd61SBrandon Streiff /* 3a73ccd61SBrandon Streiff * Marvell 88E6xxx Switch Global 2 Scratch & Misc Registers support 4a73ccd61SBrandon Streiff * 5a73ccd61SBrandon Streiff * Copyright (c) 2008 Marvell Semiconductor 6a73ccd61SBrandon Streiff * 7a73ccd61SBrandon Streiff * Copyright (c) 2017 National Instruments 8a73ccd61SBrandon Streiff * Brandon Streiff <brandon.streiff@ni.com> 9a73ccd61SBrandon Streiff */ 10a73ccd61SBrandon Streiff 11a73ccd61SBrandon Streiff #include "chip.h" 12a73ccd61SBrandon Streiff #include "global2.h" 13a73ccd61SBrandon Streiff 14a73ccd61SBrandon Streiff /* Offset 0x1A: Scratch and Misc. Register */ 15a73ccd61SBrandon Streiff static int mv88e6xxx_g2_scratch_read(struct mv88e6xxx_chip *chip, int reg, 16a73ccd61SBrandon Streiff u8 *data) 17a73ccd61SBrandon Streiff { 18a73ccd61SBrandon Streiff u16 value; 19a73ccd61SBrandon Streiff int err; 20a73ccd61SBrandon Streiff 21a73ccd61SBrandon Streiff err = mv88e6xxx_g2_write(chip, MV88E6XXX_G2_SCRATCH_MISC_MISC, 22a73ccd61SBrandon Streiff reg << 8); 23a73ccd61SBrandon Streiff if (err) 24a73ccd61SBrandon Streiff return err; 25a73ccd61SBrandon Streiff 26a73ccd61SBrandon Streiff err = mv88e6xxx_g2_read(chip, MV88E6XXX_G2_SCRATCH_MISC_MISC, &value); 27a73ccd61SBrandon Streiff if (err) 28a73ccd61SBrandon Streiff return err; 29a73ccd61SBrandon Streiff 30a73ccd61SBrandon Streiff *data = (value & MV88E6XXX_G2_SCRATCH_MISC_DATA_MASK); 31a73ccd61SBrandon Streiff 32a73ccd61SBrandon Streiff return 0; 33a73ccd61SBrandon Streiff } 34a73ccd61SBrandon Streiff 35a73ccd61SBrandon Streiff static int mv88e6xxx_g2_scratch_write(struct mv88e6xxx_chip *chip, int reg, 36a73ccd61SBrandon Streiff u8 data) 37a73ccd61SBrandon Streiff { 38a73ccd61SBrandon Streiff u16 value = (reg << 8) | data; 39a73ccd61SBrandon Streiff 402ad4da77SVivien Didelot return mv88e6xxx_g2_write(chip, MV88E6XXX_G2_SCRATCH_MISC_MISC, 412ad4da77SVivien Didelot MV88E6XXX_G2_SCRATCH_MISC_UPDATE | value); 42a73ccd61SBrandon Streiff } 43a73ccd61SBrandon Streiff 44a73ccd61SBrandon Streiff /** 453de43dc9SVladimir Oltean * mv88e6xxx_g2_scratch_get_bit - get a bit 46a73ccd61SBrandon Streiff * @chip: chip private data 470b529448SAndrew Lunn * @base_reg: base of scratch bits 480b529448SAndrew Lunn * @offset: index of bit within the register 49a73ccd61SBrandon Streiff * @set: is bit set? 50a73ccd61SBrandon Streiff */ 51a73ccd61SBrandon Streiff static int mv88e6xxx_g2_scratch_get_bit(struct mv88e6xxx_chip *chip, 52a73ccd61SBrandon Streiff int base_reg, unsigned int offset, 53a73ccd61SBrandon Streiff int *set) 54a73ccd61SBrandon Streiff { 55a73ccd61SBrandon Streiff int reg = base_reg + (offset / 8); 56a73ccd61SBrandon Streiff u8 mask = (1 << (offset & 0x7)); 57a73ccd61SBrandon Streiff u8 val; 58a73ccd61SBrandon Streiff int err; 59a73ccd61SBrandon Streiff 60a73ccd61SBrandon Streiff err = mv88e6xxx_g2_scratch_read(chip, reg, &val); 61a73ccd61SBrandon Streiff if (err) 62a73ccd61SBrandon Streiff return err; 63a73ccd61SBrandon Streiff 64a73ccd61SBrandon Streiff *set = !!(mask & val); 65a73ccd61SBrandon Streiff 66a73ccd61SBrandon Streiff return 0; 67a73ccd61SBrandon Streiff } 68a73ccd61SBrandon Streiff 69a73ccd61SBrandon Streiff /** 703de43dc9SVladimir Oltean * mv88e6xxx_g2_scratch_set_bit - set (or clear) a bit 71a73ccd61SBrandon Streiff * @chip: chip private data 720b529448SAndrew Lunn * @base_reg: base of scratch bits 730b529448SAndrew Lunn * @offset: index of bit within the register 740b529448SAndrew Lunn * @set: should this bit be set? 75a73ccd61SBrandon Streiff * 76a73ccd61SBrandon Streiff * Helper function for dealing with the direction and data registers. 77a73ccd61SBrandon Streiff */ 78a73ccd61SBrandon Streiff static int mv88e6xxx_g2_scratch_set_bit(struct mv88e6xxx_chip *chip, 79a73ccd61SBrandon Streiff int base_reg, unsigned int offset, 80a73ccd61SBrandon Streiff int set) 81a73ccd61SBrandon Streiff { 82a73ccd61SBrandon Streiff int reg = base_reg + (offset / 8); 83a73ccd61SBrandon Streiff u8 mask = (1 << (offset & 0x7)); 84a73ccd61SBrandon Streiff u8 val; 85a73ccd61SBrandon Streiff int err; 86a73ccd61SBrandon Streiff 87a73ccd61SBrandon Streiff err = mv88e6xxx_g2_scratch_read(chip, reg, &val); 88a73ccd61SBrandon Streiff if (err) 89a73ccd61SBrandon Streiff return err; 90a73ccd61SBrandon Streiff 91a73ccd61SBrandon Streiff if (set) 92a73ccd61SBrandon Streiff val |= mask; 93a73ccd61SBrandon Streiff else 94a73ccd61SBrandon Streiff val &= ~mask; 95a73ccd61SBrandon Streiff 96a73ccd61SBrandon Streiff return mv88e6xxx_g2_scratch_write(chip, reg, val); 97a73ccd61SBrandon Streiff } 98a73ccd61SBrandon Streiff 99a73ccd61SBrandon Streiff /** 100a73ccd61SBrandon Streiff * mv88e6352_g2_scratch_gpio_get_data - get data on gpio pin 101a73ccd61SBrandon Streiff * @chip: chip private data 102a73ccd61SBrandon Streiff * @pin: gpio index 103a73ccd61SBrandon Streiff * 104a73ccd61SBrandon Streiff * Return: 0 for low, 1 for high, negative error 105a73ccd61SBrandon Streiff */ 106a73ccd61SBrandon Streiff static int mv88e6352_g2_scratch_gpio_get_data(struct mv88e6xxx_chip *chip, 107a73ccd61SBrandon Streiff unsigned int pin) 108a73ccd61SBrandon Streiff { 109a73ccd61SBrandon Streiff int val = 0; 110a73ccd61SBrandon Streiff int err; 111a73ccd61SBrandon Streiff 112a73ccd61SBrandon Streiff err = mv88e6xxx_g2_scratch_get_bit(chip, 113a73ccd61SBrandon Streiff MV88E6352_G2_SCRATCH_GPIO_DATA0, 114a73ccd61SBrandon Streiff pin, &val); 115a73ccd61SBrandon Streiff if (err) 116a73ccd61SBrandon Streiff return err; 117a73ccd61SBrandon Streiff 118a73ccd61SBrandon Streiff return val; 119a73ccd61SBrandon Streiff } 120a73ccd61SBrandon Streiff 121a73ccd61SBrandon Streiff /** 122a73ccd61SBrandon Streiff * mv88e6352_g2_scratch_gpio_set_data - set data on gpio pin 123a73ccd61SBrandon Streiff * @chip: chip private data 124a73ccd61SBrandon Streiff * @pin: gpio index 125a73ccd61SBrandon Streiff * @value: value to set 126a73ccd61SBrandon Streiff */ 127a73ccd61SBrandon Streiff static int mv88e6352_g2_scratch_gpio_set_data(struct mv88e6xxx_chip *chip, 128a73ccd61SBrandon Streiff unsigned int pin, int value) 129a73ccd61SBrandon Streiff { 130a73ccd61SBrandon Streiff u8 mask = (1 << (pin & 0x7)); 131a73ccd61SBrandon Streiff int offset = (pin / 8); 132a73ccd61SBrandon Streiff int reg; 133a73ccd61SBrandon Streiff 134a73ccd61SBrandon Streiff reg = MV88E6352_G2_SCRATCH_GPIO_DATA0 + offset; 135a73ccd61SBrandon Streiff 136a73ccd61SBrandon Streiff if (value) 137a73ccd61SBrandon Streiff chip->gpio_data[offset] |= mask; 138a73ccd61SBrandon Streiff else 139a73ccd61SBrandon Streiff chip->gpio_data[offset] &= ~mask; 140a73ccd61SBrandon Streiff 141a73ccd61SBrandon Streiff return mv88e6xxx_g2_scratch_write(chip, reg, chip->gpio_data[offset]); 142a73ccd61SBrandon Streiff } 143a73ccd61SBrandon Streiff 144a73ccd61SBrandon Streiff /** 145a73ccd61SBrandon Streiff * mv88e6352_g2_scratch_gpio_get_dir - get direction of gpio pin 146a73ccd61SBrandon Streiff * @chip: chip private data 147a73ccd61SBrandon Streiff * @pin: gpio index 148a73ccd61SBrandon Streiff * 149a73ccd61SBrandon Streiff * Return: 0 for output, 1 for input (same as GPIOF_DIR_XXX). 150a73ccd61SBrandon Streiff */ 151a73ccd61SBrandon Streiff static int mv88e6352_g2_scratch_gpio_get_dir(struct mv88e6xxx_chip *chip, 152a73ccd61SBrandon Streiff unsigned int pin) 153a73ccd61SBrandon Streiff { 154a73ccd61SBrandon Streiff int val = 0; 155a73ccd61SBrandon Streiff int err; 156a73ccd61SBrandon Streiff 157a73ccd61SBrandon Streiff err = mv88e6xxx_g2_scratch_get_bit(chip, 158a73ccd61SBrandon Streiff MV88E6352_G2_SCRATCH_GPIO_DIR0, 159a73ccd61SBrandon Streiff pin, &val); 160a73ccd61SBrandon Streiff if (err) 161a73ccd61SBrandon Streiff return err; 162a73ccd61SBrandon Streiff 163a73ccd61SBrandon Streiff return val; 164a73ccd61SBrandon Streiff } 165a73ccd61SBrandon Streiff 166a73ccd61SBrandon Streiff /** 167a73ccd61SBrandon Streiff * mv88e6352_g2_scratch_gpio_set_dir - set direction of gpio pin 168a73ccd61SBrandon Streiff * @chip: chip private data 169a73ccd61SBrandon Streiff * @pin: gpio index 1700b529448SAndrew Lunn * @input: should the gpio be an input, or an output? 171a73ccd61SBrandon Streiff */ 172a73ccd61SBrandon Streiff static int mv88e6352_g2_scratch_gpio_set_dir(struct mv88e6xxx_chip *chip, 173a73ccd61SBrandon Streiff unsigned int pin, bool input) 174a73ccd61SBrandon Streiff { 175a73ccd61SBrandon Streiff int value = (input ? MV88E6352_G2_SCRATCH_GPIO_DIR_IN : 176a73ccd61SBrandon Streiff MV88E6352_G2_SCRATCH_GPIO_DIR_OUT); 177a73ccd61SBrandon Streiff 178a73ccd61SBrandon Streiff return mv88e6xxx_g2_scratch_set_bit(chip, 179a73ccd61SBrandon Streiff MV88E6352_G2_SCRATCH_GPIO_DIR0, 180a73ccd61SBrandon Streiff pin, value); 181a73ccd61SBrandon Streiff } 182a73ccd61SBrandon Streiff 183a73ccd61SBrandon Streiff /** 184a73ccd61SBrandon Streiff * mv88e6352_g2_scratch_gpio_get_pctl - get pin control setting 185a73ccd61SBrandon Streiff * @chip: chip private data 186a73ccd61SBrandon Streiff * @pin: gpio index 187a73ccd61SBrandon Streiff * @func: function number 188a73ccd61SBrandon Streiff * 189a73ccd61SBrandon Streiff * Note that the function numbers themselves may vary by chipset. 190a73ccd61SBrandon Streiff */ 191a73ccd61SBrandon Streiff static int mv88e6352_g2_scratch_gpio_get_pctl(struct mv88e6xxx_chip *chip, 192a73ccd61SBrandon Streiff unsigned int pin, int *func) 193a73ccd61SBrandon Streiff { 194a73ccd61SBrandon Streiff int reg = MV88E6352_G2_SCRATCH_GPIO_PCTL0 + (pin / 2); 195a73ccd61SBrandon Streiff int offset = (pin & 0x1) ? 4 : 0; 196a73ccd61SBrandon Streiff u8 mask = (0x7 << offset); 197a73ccd61SBrandon Streiff int err; 198a73ccd61SBrandon Streiff u8 val; 199a73ccd61SBrandon Streiff 200a73ccd61SBrandon Streiff err = mv88e6xxx_g2_scratch_read(chip, reg, &val); 201a73ccd61SBrandon Streiff if (err) 202a73ccd61SBrandon Streiff return err; 203a73ccd61SBrandon Streiff 204a73ccd61SBrandon Streiff *func = (val & mask) >> offset; 205a73ccd61SBrandon Streiff 206a73ccd61SBrandon Streiff return 0; 207a73ccd61SBrandon Streiff } 208a73ccd61SBrandon Streiff 209a73ccd61SBrandon Streiff /** 210a73ccd61SBrandon Streiff * mv88e6352_g2_scratch_gpio_set_pctl - set pin control setting 211a73ccd61SBrandon Streiff * @chip: chip private data 212a73ccd61SBrandon Streiff * @pin: gpio index 213a73ccd61SBrandon Streiff * @func: function number 214a73ccd61SBrandon Streiff */ 215a73ccd61SBrandon Streiff static int mv88e6352_g2_scratch_gpio_set_pctl(struct mv88e6xxx_chip *chip, 216a73ccd61SBrandon Streiff unsigned int pin, int func) 217a73ccd61SBrandon Streiff { 218a73ccd61SBrandon Streiff int reg = MV88E6352_G2_SCRATCH_GPIO_PCTL0 + (pin / 2); 219a73ccd61SBrandon Streiff int offset = (pin & 0x1) ? 4 : 0; 220a73ccd61SBrandon Streiff u8 mask = (0x7 << offset); 221a73ccd61SBrandon Streiff int err; 222a73ccd61SBrandon Streiff u8 val; 223a73ccd61SBrandon Streiff 224a73ccd61SBrandon Streiff err = mv88e6xxx_g2_scratch_read(chip, reg, &val); 225a73ccd61SBrandon Streiff if (err) 226a73ccd61SBrandon Streiff return err; 227a73ccd61SBrandon Streiff 228a73ccd61SBrandon Streiff val = (val & ~mask) | ((func & mask) << offset); 229a73ccd61SBrandon Streiff 230a73ccd61SBrandon Streiff return mv88e6xxx_g2_scratch_write(chip, reg, val); 231a73ccd61SBrandon Streiff } 232a73ccd61SBrandon Streiff 233a73ccd61SBrandon Streiff const struct mv88e6xxx_gpio_ops mv88e6352_gpio_ops = { 234a73ccd61SBrandon Streiff .get_data = mv88e6352_g2_scratch_gpio_get_data, 235a73ccd61SBrandon Streiff .set_data = mv88e6352_g2_scratch_gpio_set_data, 236a73ccd61SBrandon Streiff .get_dir = mv88e6352_g2_scratch_gpio_get_dir, 237a73ccd61SBrandon Streiff .set_dir = mv88e6352_g2_scratch_gpio_set_dir, 238a73ccd61SBrandon Streiff .get_pctl = mv88e6352_g2_scratch_gpio_get_pctl, 239a73ccd61SBrandon Streiff .set_pctl = mv88e6352_g2_scratch_gpio_set_pctl, 240a73ccd61SBrandon Streiff }; 2412510babcSAndrew Lunn 2422510babcSAndrew Lunn /** 2435c5b0c44SRobert Marko * mv88e6390_g2_scratch_gpio_set_smi - set gpio muxing for external smi 2442510babcSAndrew Lunn * @chip: chip private data 2452510babcSAndrew Lunn * @external: set mux for external smi, or free for gpio usage 2462510babcSAndrew Lunn * 2472510babcSAndrew Lunn * Some mv88e6xxx models have GPIO pins that may be configured as 2482510babcSAndrew Lunn * an external SMI interface, or they may be made free for other 2492510babcSAndrew Lunn * GPIO uses. 2502510babcSAndrew Lunn */ 2515c5b0c44SRobert Marko int mv88e6390_g2_scratch_gpio_set_smi(struct mv88e6xxx_chip *chip, 2522510babcSAndrew Lunn bool external) 2532510babcSAndrew Lunn { 2542510babcSAndrew Lunn int misc_cfg = MV88E6352_G2_SCRATCH_MISC_CFG; 2552510babcSAndrew Lunn int config_data1 = MV88E6352_G2_SCRATCH_CONFIG_DATA1; 2562510babcSAndrew Lunn int config_data2 = MV88E6352_G2_SCRATCH_CONFIG_DATA2; 2572510babcSAndrew Lunn bool no_cpu; 2582510babcSAndrew Lunn u8 p0_mode; 2592510babcSAndrew Lunn int err; 2602510babcSAndrew Lunn u8 val; 2612510babcSAndrew Lunn 2622510babcSAndrew Lunn err = mv88e6xxx_g2_scratch_read(chip, config_data2, &val); 2632510babcSAndrew Lunn if (err) 2642510babcSAndrew Lunn return err; 2652510babcSAndrew Lunn 2662510babcSAndrew Lunn p0_mode = val & MV88E6352_G2_SCRATCH_CONFIG_DATA2_P0_MODE_MASK; 2672510babcSAndrew Lunn 2682510babcSAndrew Lunn if (p0_mode == 0x01 || p0_mode == 0x02) 2692510babcSAndrew Lunn return -EBUSY; 2702510babcSAndrew Lunn 2712510babcSAndrew Lunn err = mv88e6xxx_g2_scratch_read(chip, config_data1, &val); 2722510babcSAndrew Lunn if (err) 2732510babcSAndrew Lunn return err; 2742510babcSAndrew Lunn 2752510babcSAndrew Lunn no_cpu = !!(val & MV88E6352_G2_SCRATCH_CONFIG_DATA1_NO_CPU); 2762510babcSAndrew Lunn 2772510babcSAndrew Lunn err = mv88e6xxx_g2_scratch_read(chip, misc_cfg, &val); 2782510babcSAndrew Lunn if (err) 2792510babcSAndrew Lunn return err; 2802510babcSAndrew Lunn 2812510babcSAndrew Lunn /* NO_CPU being 0 inverts the meaning of the bit */ 2822510babcSAndrew Lunn if (!no_cpu) 2832510babcSAndrew Lunn external = !external; 2842510babcSAndrew Lunn 2852510babcSAndrew Lunn if (external) 2862510babcSAndrew Lunn val |= MV88E6352_G2_SCRATCH_MISC_CFG_NORMALSMI; 2872510babcSAndrew Lunn else 2882510babcSAndrew Lunn val &= ~MV88E6352_G2_SCRATCH_MISC_CFG_NORMALSMI; 2892510babcSAndrew Lunn 2902510babcSAndrew Lunn return mv88e6xxx_g2_scratch_write(chip, misc_cfg, val); 2912510babcSAndrew Lunn } 29262001548SRussell King (Oracle) 29362001548SRussell King (Oracle) /** 294*e3ab3267SRobert Marko * mv88e6393x_g2_scratch_gpio_set_smi - set gpio muxing for external smi 295*e3ab3267SRobert Marko * @chip: chip private data 296*e3ab3267SRobert Marko * @external: set mux for external smi, or free for gpio usage 297*e3ab3267SRobert Marko * 298*e3ab3267SRobert Marko * MV88E6191X/6193X/6393X GPIO pins 9 and 10 can be configured as an 299*e3ab3267SRobert Marko * external SMI interface or as regular GPIO-s. 300*e3ab3267SRobert Marko * 301*e3ab3267SRobert Marko * They however have a different register layout then the existing 302*e3ab3267SRobert Marko * function. 303*e3ab3267SRobert Marko */ 304*e3ab3267SRobert Marko 305*e3ab3267SRobert Marko int mv88e6393x_g2_scratch_gpio_set_smi(struct mv88e6xxx_chip *chip, 306*e3ab3267SRobert Marko bool external) 307*e3ab3267SRobert Marko { 308*e3ab3267SRobert Marko int misc_cfg = MV88E6352_G2_SCRATCH_MISC_CFG; 309*e3ab3267SRobert Marko int err; 310*e3ab3267SRobert Marko u8 val; 311*e3ab3267SRobert Marko 312*e3ab3267SRobert Marko err = mv88e6xxx_g2_scratch_read(chip, misc_cfg, &val); 313*e3ab3267SRobert Marko if (err) 314*e3ab3267SRobert Marko return err; 315*e3ab3267SRobert Marko 316*e3ab3267SRobert Marko if (external) 317*e3ab3267SRobert Marko val &= ~MV88E6352_G2_SCRATCH_MISC_CFG_NORMALSMI; 318*e3ab3267SRobert Marko else 319*e3ab3267SRobert Marko val |= MV88E6352_G2_SCRATCH_MISC_CFG_NORMALSMI; 320*e3ab3267SRobert Marko 321*e3ab3267SRobert Marko return mv88e6xxx_g2_scratch_write(chip, misc_cfg, val); 322*e3ab3267SRobert Marko } 323*e3ab3267SRobert Marko 324*e3ab3267SRobert Marko /** 32562001548SRussell King (Oracle) * mv88e6352_g2_scratch_port_has_serdes - indicate if a port can have a serdes 32662001548SRussell King (Oracle) * @chip: chip private data 32762001548SRussell King (Oracle) * @port: port number to check for serdes 32862001548SRussell King (Oracle) * 32962001548SRussell King (Oracle) * Indicates whether the port may have a serdes attached according to the 33062001548SRussell King (Oracle) * pin strapping. Returns negative error number, 0 if the port is not 33162001548SRussell King (Oracle) * configured to have a serdes, and 1 if the port is configured to have a 33262001548SRussell King (Oracle) * serdes attached. 33362001548SRussell King (Oracle) */ 33462001548SRussell King (Oracle) int mv88e6352_g2_scratch_port_has_serdes(struct mv88e6xxx_chip *chip, int port) 33562001548SRussell King (Oracle) { 33662001548SRussell King (Oracle) u8 config3, p; 33762001548SRussell King (Oracle) int err; 33862001548SRussell King (Oracle) 33962001548SRussell King (Oracle) err = mv88e6xxx_g2_scratch_read(chip, MV88E6352_G2_SCRATCH_CONFIG_DATA3, 34062001548SRussell King (Oracle) &config3); 34162001548SRussell King (Oracle) if (err) 34262001548SRussell King (Oracle) return err; 34362001548SRussell King (Oracle) 34462001548SRussell King (Oracle) if (config3 & MV88E6352_G2_SCRATCH_CONFIG_DATA3_S_SEL) 34562001548SRussell King (Oracle) p = 5; 34662001548SRussell King (Oracle) else 34762001548SRussell King (Oracle) p = 4; 34862001548SRussell King (Oracle) 34962001548SRussell King (Oracle) return port == p; 35062001548SRussell King (Oracle) } 351