Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /*
0003  * Marvell 88E6xxx Switch Global 2 Scratch & Misc Registers support
0004  *
0005  * Copyright (c) 2008 Marvell Semiconductor
0006  *
0007  * Copyright (c) 2017 National Instruments
0008  *      Brandon Streiff <brandon.streiff@ni.com>
0009  */
0010 
0011 #include "chip.h"
0012 #include "global2.h"
0013 
0014 /* Offset 0x1A: Scratch and Misc. Register */
0015 static int mv88e6xxx_g2_scratch_read(struct mv88e6xxx_chip *chip, int reg,
0016                      u8 *data)
0017 {
0018     u16 value;
0019     int err;
0020 
0021     err = mv88e6xxx_g2_write(chip, MV88E6XXX_G2_SCRATCH_MISC_MISC,
0022                  reg << 8);
0023     if (err)
0024         return err;
0025 
0026     err = mv88e6xxx_g2_read(chip, MV88E6XXX_G2_SCRATCH_MISC_MISC, &value);
0027     if (err)
0028         return err;
0029 
0030     *data = (value & MV88E6XXX_G2_SCRATCH_MISC_DATA_MASK);
0031 
0032     return 0;
0033 }
0034 
0035 static int mv88e6xxx_g2_scratch_write(struct mv88e6xxx_chip *chip, int reg,
0036                       u8 data)
0037 {
0038     u16 value = (reg << 8) | data;
0039 
0040     return mv88e6xxx_g2_write(chip, MV88E6XXX_G2_SCRATCH_MISC_MISC,
0041                   MV88E6XXX_G2_SCRATCH_MISC_UPDATE | value);
0042 }
0043 
0044 /**
0045  * mv88e6xxx_g2_scratch_get_bit - get a bit
0046  * @chip: chip private data
0047  * @base_reg: base of scratch bits
0048  * @offset: index of bit within the register
0049  * @set: is bit set?
0050  */
0051 static int mv88e6xxx_g2_scratch_get_bit(struct mv88e6xxx_chip *chip,
0052                     int base_reg, unsigned int offset,
0053                     int *set)
0054 {
0055     int reg = base_reg + (offset / 8);
0056     u8 mask = (1 << (offset & 0x7));
0057     u8 val;
0058     int err;
0059 
0060     err = mv88e6xxx_g2_scratch_read(chip, reg, &val);
0061     if (err)
0062         return err;
0063 
0064     *set = !!(mask & val);
0065 
0066     return 0;
0067 }
0068 
0069 /**
0070  * mv88e6xxx_g2_scratch_set_bit - set (or clear) a bit
0071  * @chip: chip private data
0072  * @base_reg: base of scratch bits
0073  * @offset: index of bit within the register
0074  * @set: should this bit be set?
0075  *
0076  * Helper function for dealing with the direction and data registers.
0077  */
0078 static int mv88e6xxx_g2_scratch_set_bit(struct mv88e6xxx_chip *chip,
0079                     int base_reg, unsigned int offset,
0080                     int set)
0081 {
0082     int reg = base_reg + (offset / 8);
0083     u8 mask = (1 << (offset & 0x7));
0084     u8 val;
0085     int err;
0086 
0087     err = mv88e6xxx_g2_scratch_read(chip, reg, &val);
0088     if (err)
0089         return err;
0090 
0091     if (set)
0092         val |= mask;
0093     else
0094         val &= ~mask;
0095 
0096     return mv88e6xxx_g2_scratch_write(chip, reg, val);
0097 }
0098 
0099 /**
0100  * mv88e6352_g2_scratch_gpio_get_data - get data on gpio pin
0101  * @chip: chip private data
0102  * @pin: gpio index
0103  *
0104  * Return: 0 for low, 1 for high, negative error
0105  */
0106 static int mv88e6352_g2_scratch_gpio_get_data(struct mv88e6xxx_chip *chip,
0107                           unsigned int pin)
0108 {
0109     int val = 0;
0110     int err;
0111 
0112     err = mv88e6xxx_g2_scratch_get_bit(chip,
0113                        MV88E6352_G2_SCRATCH_GPIO_DATA0,
0114                        pin, &val);
0115     if (err)
0116         return err;
0117 
0118     return val;
0119 }
0120 
0121 /**
0122  * mv88e6352_g2_scratch_gpio_set_data - set data on gpio pin
0123  * @chip: chip private data
0124  * @pin: gpio index
0125  * @value: value to set
0126  */
0127 static int mv88e6352_g2_scratch_gpio_set_data(struct mv88e6xxx_chip *chip,
0128                           unsigned int pin, int value)
0129 {
0130     u8 mask = (1 << (pin & 0x7));
0131     int offset = (pin / 8);
0132     int reg;
0133 
0134     reg = MV88E6352_G2_SCRATCH_GPIO_DATA0 + offset;
0135 
0136     if (value)
0137         chip->gpio_data[offset] |= mask;
0138     else
0139         chip->gpio_data[offset] &= ~mask;
0140 
0141     return mv88e6xxx_g2_scratch_write(chip, reg, chip->gpio_data[offset]);
0142 }
0143 
0144 /**
0145  * mv88e6352_g2_scratch_gpio_get_dir - get direction of gpio pin
0146  * @chip: chip private data
0147  * @pin: gpio index
0148  *
0149  * Return: 0 for output, 1 for input (same as GPIOF_DIR_XXX).
0150  */
0151 static int mv88e6352_g2_scratch_gpio_get_dir(struct mv88e6xxx_chip *chip,
0152                          unsigned int pin)
0153 {
0154     int val = 0;
0155     int err;
0156 
0157     err = mv88e6xxx_g2_scratch_get_bit(chip,
0158                        MV88E6352_G2_SCRATCH_GPIO_DIR0,
0159                        pin, &val);
0160     if (err)
0161         return err;
0162 
0163     return val;
0164 }
0165 
0166 /**
0167  * mv88e6352_g2_scratch_gpio_set_dir - set direction of gpio pin
0168  * @chip: chip private data
0169  * @pin: gpio index
0170  * @input: should the gpio be an input, or an output?
0171  */
0172 static int mv88e6352_g2_scratch_gpio_set_dir(struct mv88e6xxx_chip *chip,
0173                          unsigned int pin, bool input)
0174 {
0175     int value = (input ? MV88E6352_G2_SCRATCH_GPIO_DIR_IN :
0176                  MV88E6352_G2_SCRATCH_GPIO_DIR_OUT);
0177 
0178     return mv88e6xxx_g2_scratch_set_bit(chip,
0179                         MV88E6352_G2_SCRATCH_GPIO_DIR0,
0180                         pin, value);
0181 }
0182 
0183 /**
0184  * mv88e6352_g2_scratch_gpio_get_pctl - get pin control setting
0185  * @chip: chip private data
0186  * @pin: gpio index
0187  * @func: function number
0188  *
0189  * Note that the function numbers themselves may vary by chipset.
0190  */
0191 static int mv88e6352_g2_scratch_gpio_get_pctl(struct mv88e6xxx_chip *chip,
0192                           unsigned int pin, int *func)
0193 {
0194     int reg = MV88E6352_G2_SCRATCH_GPIO_PCTL0 + (pin / 2);
0195     int offset = (pin & 0x1) ? 4 : 0;
0196     u8 mask = (0x7 << offset);
0197     int err;
0198     u8 val;
0199 
0200     err = mv88e6xxx_g2_scratch_read(chip, reg, &val);
0201     if (err)
0202         return err;
0203 
0204     *func = (val & mask) >> offset;
0205 
0206     return 0;
0207 }
0208 
0209 /**
0210  * mv88e6352_g2_scratch_gpio_set_pctl - set pin control setting
0211  * @chip: chip private data
0212  * @pin: gpio index
0213  * @func: function number
0214  */
0215 static int mv88e6352_g2_scratch_gpio_set_pctl(struct mv88e6xxx_chip *chip,
0216                           unsigned int pin, int func)
0217 {
0218     int reg = MV88E6352_G2_SCRATCH_GPIO_PCTL0 + (pin / 2);
0219     int offset = (pin & 0x1) ? 4 : 0;
0220     u8 mask = (0x7 << offset);
0221     int err;
0222     u8 val;
0223 
0224     err = mv88e6xxx_g2_scratch_read(chip, reg, &val);
0225     if (err)
0226         return err;
0227 
0228     val = (val & ~mask) | ((func & mask) << offset);
0229 
0230     return mv88e6xxx_g2_scratch_write(chip, reg, val);
0231 }
0232 
0233 const struct mv88e6xxx_gpio_ops mv88e6352_gpio_ops = {
0234     .get_data = mv88e6352_g2_scratch_gpio_get_data,
0235     .set_data = mv88e6352_g2_scratch_gpio_set_data,
0236     .get_dir = mv88e6352_g2_scratch_gpio_get_dir,
0237     .set_dir = mv88e6352_g2_scratch_gpio_set_dir,
0238     .get_pctl = mv88e6352_g2_scratch_gpio_get_pctl,
0239     .set_pctl = mv88e6352_g2_scratch_gpio_set_pctl,
0240 };
0241 
0242 /**
0243  * mv88e6xxx_g2_scratch_gpio_set_smi - set gpio muxing for external smi
0244  * @chip: chip private data
0245  * @external: set mux for external smi, or free for gpio usage
0246  *
0247  * Some mv88e6xxx models have GPIO pins that may be configured as
0248  * an external SMI interface, or they may be made free for other
0249  * GPIO uses.
0250  */
0251 int mv88e6xxx_g2_scratch_gpio_set_smi(struct mv88e6xxx_chip *chip,
0252                       bool external)
0253 {
0254     int misc_cfg = MV88E6352_G2_SCRATCH_MISC_CFG;
0255     int config_data1 = MV88E6352_G2_SCRATCH_CONFIG_DATA1;
0256     int config_data2 = MV88E6352_G2_SCRATCH_CONFIG_DATA2;
0257     bool no_cpu;
0258     u8 p0_mode;
0259     int err;
0260     u8 val;
0261 
0262     err = mv88e6xxx_g2_scratch_read(chip, config_data2, &val);
0263     if (err)
0264         return err;
0265 
0266     p0_mode = val & MV88E6352_G2_SCRATCH_CONFIG_DATA2_P0_MODE_MASK;
0267 
0268     if (p0_mode == 0x01 || p0_mode == 0x02)
0269         return -EBUSY;
0270 
0271     err = mv88e6xxx_g2_scratch_read(chip, config_data1, &val);
0272     if (err)
0273         return err;
0274 
0275     no_cpu = !!(val & MV88E6352_G2_SCRATCH_CONFIG_DATA1_NO_CPU);
0276 
0277     err = mv88e6xxx_g2_scratch_read(chip, misc_cfg, &val);
0278     if (err)
0279         return err;
0280 
0281     /* NO_CPU being 0 inverts the meaning of the bit */
0282     if (!no_cpu)
0283         external = !external;
0284 
0285     if (external)
0286         val |= MV88E6352_G2_SCRATCH_MISC_CFG_NORMALSMI;
0287     else
0288         val &= ~MV88E6352_G2_SCRATCH_MISC_CFG_NORMALSMI;
0289 
0290     return mv88e6xxx_g2_scratch_write(chip, misc_cfg, val);
0291 }
0292 
0293 /**
0294  * mv88e6352_g2_scratch_port_has_serdes - indicate if a port can have a serdes
0295  * @chip: chip private data
0296  * @port: port number to check for serdes
0297  *
0298  * Indicates whether the port may have a serdes attached according to the
0299  * pin strapping. Returns negative error number, 0 if the port is not
0300  * configured to have a serdes, and 1 if the port is configured to have a
0301  * serdes attached.
0302  */
0303 int mv88e6352_g2_scratch_port_has_serdes(struct mv88e6xxx_chip *chip, int port)
0304 {
0305     u8 config3, p;
0306     int err;
0307 
0308     err = mv88e6xxx_g2_scratch_read(chip, MV88E6352_G2_SCRATCH_CONFIG_DATA3,
0309                     &config3);
0310     if (err)
0311         return err;
0312 
0313     if (config3 & MV88E6352_G2_SCRATCH_CONFIG_DATA3_S_SEL)
0314         p = 5;
0315     else
0316         p = 4;
0317 
0318     return port == p;
0319 }