uboot/drivers/net/phy/mv88e6352.c
<<
>>
Prefs
   1/*
   2 * (C) Copyright 2012
   3 * Valentin Lontgchamp, Keymile AG, valentin.longchamp@keymile.com
   4 *
   5 * SPDX-License-Identifier:     GPL-2.0+
   6 */
   7
   8#include <common.h>
   9#include <miiphy.h>
  10#include <linux/errno.h>
  11#include <mv88e6352.h>
  12
  13#define SMI_HDR         ((0x8 | 0x1) << 12)
  14#define SMI_BUSY_MASK   (0x8000)
  15#define SMIRD_OP        (0x2 << 10)
  16#define SMIWR_OP        (0x1 << 10)
  17#define SMI_MASK        0x1f
  18#define PORT_SHIFT      5
  19
  20#define COMMAND_REG     0
  21#define DATA_REG        1
  22
  23/* global registers */
  24#define GLOBAL          0x1b
  25
  26#define GLOBAL_STATUS   0x00
  27#define PPU_STATE       0x8000
  28
  29#define GLOBAL_CTRL     0x04
  30#define SW_RESET        0x8000
  31#define PPU_ENABLE      0x4000
  32
  33static int sw_wait_rdy(const char *devname, u8 phy_addr)
  34{
  35        u16 command;
  36        u32 timeout = 100;
  37        int ret;
  38
  39        /* wait till the SMI is not busy */
  40        do {
  41                /* read command register */
  42                ret = miiphy_read(devname, phy_addr, COMMAND_REG, &command);
  43                if (ret < 0) {
  44                        printf("%s: Error reading command register\n",
  45                                __func__);
  46                        return ret;
  47                }
  48                if (timeout-- == 0) {
  49                        printf("Err..(%s) SMI busy timeout\n", __func__);
  50                        return -EFAULT;
  51                }
  52        } while (command & SMI_BUSY_MASK);
  53
  54        return 0;
  55}
  56
  57static int sw_reg_read(const char *devname, u8 phy_addr, u8 port,
  58        u8 reg, u16 *data)
  59{
  60        int ret;
  61        u16 command;
  62
  63        ret = sw_wait_rdy(devname, phy_addr);
  64        if (ret)
  65                return ret;
  66
  67        command = SMI_HDR | SMIRD_OP | ((port&SMI_MASK) << PORT_SHIFT) |
  68                        (reg & SMI_MASK);
  69        debug("%s: write to command: %#x\n", __func__, command);
  70        ret = miiphy_write(devname, phy_addr, COMMAND_REG, command);
  71        if (ret)
  72                return ret;
  73
  74        ret = sw_wait_rdy(devname, phy_addr);
  75        if (ret)
  76                return ret;
  77
  78        ret = miiphy_read(devname, phy_addr, DATA_REG, data);
  79
  80        return ret;
  81}
  82
  83static int sw_reg_write(const char *devname, u8 phy_addr, u8 port,
  84        u8 reg, u16 data)
  85{
  86        int ret;
  87        u16 value;
  88
  89        ret = sw_wait_rdy(devname, phy_addr);
  90        if (ret)
  91                return ret;
  92
  93        debug("%s: write to data: %#x\n", __func__, data);
  94        ret = miiphy_write(devname, phy_addr, DATA_REG, data);
  95        if (ret)
  96                return ret;
  97
  98        value = SMI_HDR | SMIWR_OP | ((port & SMI_MASK) << PORT_SHIFT) |
  99                        (reg & SMI_MASK);
 100        debug("%s: write to command: %#x\n", __func__, value);
 101        ret = miiphy_write(devname, phy_addr, COMMAND_REG, value);
 102        if (ret)
 103                return ret;
 104
 105        ret = sw_wait_rdy(devname, phy_addr);
 106        if (ret)
 107                return ret;
 108
 109        return 0;
 110}
 111
 112static int ppu_enable(const char *devname, u8 phy_addr)
 113{
 114        int i, ret = 0;
 115        u16 reg;
 116
 117        ret = sw_reg_read(devname, phy_addr, GLOBAL, GLOBAL_CTRL, &reg);
 118        if (ret) {
 119                printf("%s: Error reading global ctrl reg\n", __func__);
 120                return ret;
 121        }
 122
 123        reg |= PPU_ENABLE;
 124
 125        ret = sw_reg_write(devname, phy_addr, GLOBAL, GLOBAL_CTRL, reg);
 126        if (ret) {
 127                printf("%s: Error writing global ctrl reg\n", __func__);
 128                return ret;
 129        }
 130
 131        for (i = 0; i < 1000; i++) {
 132                sw_reg_read(devname, phy_addr, GLOBAL, GLOBAL_STATUS,
 133                        &reg);
 134                if ((reg & 0xc000) == 0xc000)
 135                        return 0;
 136                udelay(1000);
 137        }
 138
 139        return -ETIMEDOUT;
 140}
 141
 142static int ppu_disable(const char *devname, u8 phy_addr)
 143{
 144        int i, ret = 0;
 145        u16 reg;
 146
 147        ret = sw_reg_read(devname, phy_addr, GLOBAL, GLOBAL_CTRL, &reg);
 148        if (ret) {
 149                printf("%s: Error reading global ctrl reg\n", __func__);
 150                return ret;
 151        }
 152
 153        reg &= ~PPU_ENABLE;
 154
 155        ret = sw_reg_write(devname, phy_addr, GLOBAL, GLOBAL_CTRL, reg);
 156        if (ret) {
 157                printf("%s: Error writing global ctrl reg\n", __func__);
 158                return ret;
 159        }
 160
 161        for (i = 0; i < 1000; i++) {
 162                sw_reg_read(devname, phy_addr, GLOBAL, GLOBAL_STATUS,
 163                        &reg);
 164                if ((reg & 0xc000) != 0xc000)
 165                        return 0;
 166                udelay(1000);
 167        }
 168
 169        return -ETIMEDOUT;
 170}
 171
 172int mv88e_sw_program(const char *devname, u8 phy_addr,
 173        struct mv88e_sw_reg *regs, int regs_nb)
 174{
 175        int i, ret = 0;
 176
 177        /* first we need to disable the PPU */
 178        ret = ppu_disable(devname, phy_addr);
 179        if (ret) {
 180                printf("%s: Error disabling PPU\n", __func__);
 181                return ret;
 182        }
 183
 184        for (i = 0; i < regs_nb; i++) {
 185                ret = sw_reg_write(devname, phy_addr, regs[i].port,
 186                        regs[i].reg, regs[i].value);
 187                if (ret) {
 188                        printf("%s: Error configuring switch\n", __func__);
 189                        ppu_enable(devname, phy_addr);
 190                        return ret;
 191                }
 192        }
 193
 194        /* re-enable the PPU */
 195        ret = ppu_enable(devname, phy_addr);
 196        if (ret) {
 197                printf("%s: Error enabling PPU\n", __func__);
 198                return ret;
 199        }
 200
 201        return 0;
 202}
 203
 204int mv88e_sw_reset(const char *devname, u8 phy_addr)
 205{
 206        int i, ret = 0;
 207        u16 reg;
 208
 209        ret = sw_reg_read(devname, phy_addr, GLOBAL, GLOBAL_CTRL, &reg);
 210        if (ret) {
 211                printf("%s: Error reading global ctrl reg\n", __func__);
 212                return ret;
 213        }
 214
 215        reg = SW_RESET | PPU_ENABLE | 0x0400;
 216
 217        ret = sw_reg_write(devname, phy_addr, GLOBAL, GLOBAL_CTRL, reg);
 218        if (ret) {
 219                printf("%s: Error writing global ctrl reg\n", __func__);
 220                return ret;
 221        }
 222
 223        for (i = 0; i < 1000; i++) {
 224                sw_reg_read(devname, phy_addr, GLOBAL, GLOBAL_STATUS,
 225                        &reg);
 226                if ((reg & 0xc800) != 0xc800)
 227                        return 0;
 228                udelay(1000);
 229        }
 230
 231        return -ETIMEDOUT;
 232}
 233
 234int do_mvsw_reg_read(const char *name, int argc, char * const argv[])
 235{
 236        u16 value = 0, phyaddr, reg, port;
 237        int ret;
 238
 239        phyaddr = simple_strtoul(argv[1], NULL, 10);
 240        port = simple_strtoul(argv[2], NULL, 10);
 241        reg = simple_strtoul(argv[3], NULL, 10);
 242
 243        ret = sw_reg_read(name, phyaddr, port, reg, &value);
 244        printf("%#x\n", value);
 245
 246        return ret;
 247}
 248
 249int do_mvsw_reg_write(const char *name, int argc, char * const argv[])
 250{
 251        u16 value = 0, phyaddr, reg, port;
 252        int ret;
 253
 254        phyaddr = simple_strtoul(argv[1], NULL, 10);
 255        port = simple_strtoul(argv[2], NULL, 10);
 256        reg = simple_strtoul(argv[3], NULL, 10);
 257        value = simple_strtoul(argv[4], NULL, 16);
 258
 259        ret = sw_reg_write(name, phyaddr, port, reg, value);
 260
 261        return ret;
 262}
 263
 264
 265int do_mvsw_reg(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
 266{
 267        int ret;
 268        const char *cmd, *ethname;
 269
 270        if (argc < 2)
 271                return cmd_usage(cmdtp);
 272
 273        cmd = argv[1];
 274        --argc;
 275        ++argv;
 276
 277        if (strcmp(cmd, "read") == 0) {
 278                if (argc < 5)
 279                        return cmd_usage(cmdtp);
 280                ethname = argv[1];
 281                --argc;
 282                ++argv;
 283                ret = do_mvsw_reg_read(ethname, argc, argv);
 284        } else if (strcmp(cmd, "write") == 0) {
 285                if (argc < 6)
 286                        return cmd_usage(cmdtp);
 287                ethname = argv[1];
 288                --argc;
 289                ++argv;
 290                ret = do_mvsw_reg_write(ethname, argc, argv);
 291        } else
 292                return cmd_usage(cmdtp);
 293
 294        return ret;
 295}
 296
 297U_BOOT_CMD(
 298        mvsw_reg,       7,      1,      do_mvsw_reg,
 299        "marvell 88e6352 switch register access",
 300        "write ethname phyaddr port reg value\n"
 301        "mvsw_reg read  ethname phyaddr port reg\n"
 302        );
 303