1/* 2 * net/dsa/mv88e6131.c - Marvell 88e6095/6095f/6131 switch chip support 3 * Copyright (c) 2008-2009 Marvell Semiconductor 4 * 5 * This program is free software; you can redistribute it and/or modify 6 * it under the terms of the GNU General Public License as published by 7 * the Free Software Foundation; either version 2 of the License, or 8 * (at your option) any later version. 9 */ 10 11#include <linux/delay.h> 12#include <linux/jiffies.h> 13#include <linux/list.h> 14#include <linux/module.h> 15#include <linux/netdevice.h> 16#include <linux/phy.h> 17#include <net/dsa.h> 18#include "mv88e6xxx.h" 19 20static const struct mv88e6xxx_switch_id mv88e6131_table[] = { 21 { PORT_SWITCH_ID_6085, "Marvell 88E6085" }, 22 { PORT_SWITCH_ID_6095, "Marvell 88E6095/88E6095F" }, 23 { PORT_SWITCH_ID_6131, "Marvell 88E6131" }, 24 { PORT_SWITCH_ID_6131_B2, "Marvell 88E6131 (B2)" }, 25 { PORT_SWITCH_ID_6185, "Marvell 88E6185" }, 26}; 27 28static char *mv88e6131_probe(struct device *host_dev, int sw_addr) 29{ 30 return mv88e6xxx_lookup_name(host_dev, sw_addr, mv88e6131_table, 31 ARRAY_SIZE(mv88e6131_table)); 32} 33 34static int mv88e6131_setup_global(struct dsa_switch *ds) 35{ 36 u32 upstream_port = dsa_upstream_port(ds); 37 int ret; 38 u32 reg; 39 40 ret = mv88e6xxx_setup_global(ds); 41 if (ret) 42 return ret; 43 44 /* Enable the PHY polling unit, don't discard packets with 45 * excessive collisions, use a weighted fair queueing scheme 46 * to arbitrate between packet queues, set the maximum frame 47 * size to 1632, and mask all interrupt sources. 48 */ 49 REG_WRITE(REG_GLOBAL, GLOBAL_CONTROL, 50 GLOBAL_CONTROL_PPU_ENABLE | GLOBAL_CONTROL_MAX_FRAME_1632); 51 52 /* Set the VLAN ethertype to 0x8100. */ 53 REG_WRITE(REG_GLOBAL, GLOBAL_CORE_TAG_TYPE, 0x8100); 54 55 /* Disable ARP mirroring, and configure the upstream port as 56 * the port to which ingress and egress monitor frames are to 57 * be sent. 58 */ 59 reg = upstream_port << GLOBAL_MONITOR_CONTROL_INGRESS_SHIFT | 60 upstream_port << GLOBAL_MONITOR_CONTROL_EGRESS_SHIFT | 61 GLOBAL_MONITOR_CONTROL_ARP_DISABLED; 62 REG_WRITE(REG_GLOBAL, GLOBAL_MONITOR_CONTROL, reg); 63 64 /* Disable cascade port functionality unless this device 65 * is used in a cascade configuration, and set the switch's 66 * DSA device number. 67 */ 68 if (ds->dst->pd->nr_chips > 1) 69 REG_WRITE(REG_GLOBAL, GLOBAL_CONTROL_2, 70 GLOBAL_CONTROL_2_MULTIPLE_CASCADE | 71 (ds->index & 0x1f)); 72 else 73 REG_WRITE(REG_GLOBAL, GLOBAL_CONTROL_2, 74 GLOBAL_CONTROL_2_NO_CASCADE | 75 (ds->index & 0x1f)); 76 77 /* Force the priority of IGMP/MLD snoop frames and ARP frames 78 * to the highest setting. 79 */ 80 REG_WRITE(REG_GLOBAL2, GLOBAL2_PRIO_OVERRIDE, 81 GLOBAL2_PRIO_OVERRIDE_FORCE_SNOOP | 82 7 << GLOBAL2_PRIO_OVERRIDE_SNOOP_SHIFT | 83 GLOBAL2_PRIO_OVERRIDE_FORCE_ARP | 84 7 << GLOBAL2_PRIO_OVERRIDE_ARP_SHIFT); 85 86 return 0; 87} 88 89static int mv88e6131_setup(struct dsa_switch *ds) 90{ 91 struct mv88e6xxx_priv_state *ps = ds_to_priv(ds); 92 int ret; 93 94 ret = mv88e6xxx_setup_common(ds); 95 if (ret < 0) 96 return ret; 97 98 mv88e6xxx_ppu_state_init(ds); 99 100 switch (ps->id) { 101 case PORT_SWITCH_ID_6085: 102 case PORT_SWITCH_ID_6185: 103 ps->num_ports = 10; 104 break; 105 case PORT_SWITCH_ID_6095: 106 ps->num_ports = 11; 107 break; 108 case PORT_SWITCH_ID_6131: 109 case PORT_SWITCH_ID_6131_B2: 110 ps->num_ports = 8; 111 break; 112 default: 113 return -ENODEV; 114 } 115 116 ret = mv88e6xxx_switch_reset(ds, false); 117 if (ret < 0) 118 return ret; 119 120 ret = mv88e6131_setup_global(ds); 121 if (ret < 0) 122 return ret; 123 124 return mv88e6xxx_setup_ports(ds); 125} 126 127static int mv88e6131_port_to_phy_addr(struct dsa_switch *ds, int port) 128{ 129 struct mv88e6xxx_priv_state *ps = ds_to_priv(ds); 130 131 if (port >= 0 && port < ps->num_ports) 132 return port; 133 134 return -EINVAL; 135} 136 137static int 138mv88e6131_phy_read(struct dsa_switch *ds, int port, int regnum) 139{ 140 int addr = mv88e6131_port_to_phy_addr(ds, port); 141 142 if (addr < 0) 143 return addr; 144 145 return mv88e6xxx_phy_read_ppu(ds, addr, regnum); 146} 147 148static int 149mv88e6131_phy_write(struct dsa_switch *ds, 150 int port, int regnum, u16 val) 151{ 152 int addr = mv88e6131_port_to_phy_addr(ds, port); 153 154 if (addr < 0) 155 return addr; 156 157 return mv88e6xxx_phy_write_ppu(ds, addr, regnum, val); 158} 159 160struct dsa_switch_driver mv88e6131_switch_driver = { 161 .tag_protocol = DSA_TAG_PROTO_DSA, 162 .priv_size = sizeof(struct mv88e6xxx_priv_state), 163 .probe = mv88e6131_probe, 164 .setup = mv88e6131_setup, 165 .set_addr = mv88e6xxx_set_addr_direct, 166 .phy_read = mv88e6131_phy_read, 167 .phy_write = mv88e6131_phy_write, 168 .get_strings = mv88e6xxx_get_strings, 169 .get_ethtool_stats = mv88e6xxx_get_ethtool_stats, 170 .get_sset_count = mv88e6xxx_get_sset_count, 171 .adjust_link = mv88e6xxx_adjust_link, 172}; 173 174MODULE_ALIAS("platform:mv88e6085"); 175MODULE_ALIAS("platform:mv88e6095"); 176MODULE_ALIAS("platform:mv88e6095f"); 177MODULE_ALIAS("platform:mv88e6131"); 178