blob: a7da81248bcfd1fb1b69bfaf8115a2d337fdeb8c [file] [log] [blame]
Vivien Didelot18abed22016-11-04 03:23:26 +01001/*
2 * Marvell 88E6xxx Switch Port Registers support
3 *
4 * Copyright (c) 2008 Marvell Semiconductor
5 *
6 * Copyright (c) 2016 Vivien Didelot <vivien.didelot@savoirfairelinux.com>
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 */
13
14#include "mv88e6xxx.h"
15#include "port.h"
16
17int mv88e6xxx_port_read(struct mv88e6xxx_chip *chip, int port, int reg,
18 u16 *val)
19{
20 int addr = chip->info->port_base_addr + port;
21
22 return mv88e6xxx_read(chip, addr, reg, val);
23}
24
25int mv88e6xxx_port_write(struct mv88e6xxx_chip *chip, int port, int reg,
26 u16 val)
27{
28 int addr = chip->info->port_base_addr + port;
29
30 return mv88e6xxx_write(chip, addr, reg, val);
31}
Vivien Didelote28def332016-11-04 03:23:27 +010032
33/* Offset 0x04: Port Control Register */
34
35static const char * const mv88e6xxx_port_state_names[] = {
36 [PORT_CONTROL_STATE_DISABLED] = "Disabled",
37 [PORT_CONTROL_STATE_BLOCKING] = "Blocking/Listening",
38 [PORT_CONTROL_STATE_LEARNING] = "Learning",
39 [PORT_CONTROL_STATE_FORWARDING] = "Forwarding",
40};
41
42int mv88e6xxx_port_set_state(struct mv88e6xxx_chip *chip, int port, u8 state)
43{
44 u16 reg;
45 int err;
46
47 err = mv88e6xxx_port_read(chip, port, PORT_CONTROL, &reg);
48 if (err)
49 return err;
50
51 reg &= ~PORT_CONTROL_STATE_MASK;
52 reg |= state;
53
54 err = mv88e6xxx_port_write(chip, port, PORT_CONTROL, reg);
55 if (err)
56 return err;
57
58 netdev_dbg(chip->ds->ports[port].netdev, "PortState set to %s\n",
59 mv88e6xxx_port_state_names[state]);
60
61 return 0;
62}
Vivien Didelot5a7921f2016-11-04 03:23:28 +010063
Vivien Didelotb4e48c52016-11-04 03:23:29 +010064/* Offset 0x05: Port Control 1 */
65
Vivien Didelot5a7921f2016-11-04 03:23:28 +010066/* Offset 0x06: Port Based VLAN Map */
67
68int mv88e6xxx_port_set_vlan_map(struct mv88e6xxx_chip *chip, int port, u16 map)
69{
70 const u16 mask = GENMASK(mv88e6xxx_num_ports(chip) - 1, 0);
71 u16 reg;
72 int err;
73
74 err = mv88e6xxx_port_read(chip, port, PORT_BASE_VLAN, &reg);
75 if (err)
76 return err;
77
78 reg &= ~mask;
79 reg |= map & mask;
80
81 err = mv88e6xxx_port_write(chip, port, PORT_BASE_VLAN, reg);
82 if (err)
83 return err;
84
85 netdev_dbg(chip->ds->ports[port].netdev, "VLANTable set to %.3x\n",
86 map);
87
88 return 0;
89}
Vivien Didelotb4e48c52016-11-04 03:23:29 +010090
91int mv88e6xxx_port_get_fid(struct mv88e6xxx_chip *chip, int port, u16 *fid)
92{
93 const u16 upper_mask = (mv88e6xxx_num_databases(chip) - 1) >> 4;
94 u16 reg;
95 int err;
96
97 /* Port's default FID lower 4 bits are located in reg 0x06, offset 12 */
98 err = mv88e6xxx_port_read(chip, port, PORT_BASE_VLAN, &reg);
99 if (err)
100 return err;
101
102 *fid = (reg & 0xf000) >> 12;
103
104 /* Port's default FID upper bits are located in reg 0x05, offset 0 */
105 if (upper_mask) {
106 err = mv88e6xxx_port_read(chip, port, PORT_CONTROL_1, &reg);
107 if (err)
108 return err;
109
110 *fid |= (reg & upper_mask) << 4;
111 }
112
113 return 0;
114}
115
116int mv88e6xxx_port_set_fid(struct mv88e6xxx_chip *chip, int port, u16 fid)
117{
118 const u16 upper_mask = (mv88e6xxx_num_databases(chip) - 1) >> 4;
119 u16 reg;
120 int err;
121
122 if (fid >= mv88e6xxx_num_databases(chip))
123 return -EINVAL;
124
125 /* Port's default FID lower 4 bits are located in reg 0x06, offset 12 */
126 err = mv88e6xxx_port_read(chip, port, PORT_BASE_VLAN, &reg);
127 if (err)
128 return err;
129
130 reg &= 0x0fff;
131 reg |= (fid & 0x000f) << 12;
132
133 err = mv88e6xxx_port_write(chip, port, PORT_BASE_VLAN, reg);
134 if (err)
135 return err;
136
137 /* Port's default FID upper bits are located in reg 0x05, offset 0 */
138 if (upper_mask) {
139 err = mv88e6xxx_port_read(chip, port, PORT_CONTROL_1, &reg);
140 if (err)
141 return err;
142
143 reg &= ~upper_mask;
144 reg |= (fid >> 4) & upper_mask;
145
146 err = mv88e6xxx_port_write(chip, port, PORT_CONTROL_1, reg);
147 if (err)
148 return err;
149 }
150
151 netdev_dbg(chip->ds->ports[port].netdev, "FID set to %u\n", fid);
152
153 return 0;
154}