GNU Linux-libre 6.8.9-gnu
[releases.git] / drivers / net / dsa / mv88e6xxx / global2_avb.c
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3  * Marvell 88E6xxx Switch Global 2 Registers support
4  *
5  * Copyright (c) 2008 Marvell Semiconductor
6  *
7  * Copyright (c) 2016-2017 Savoir-faire Linux Inc.
8  *      Vivien Didelot <vivien.didelot@savoirfairelinux.com>
9  *
10  * Copyright (c) 2017 National Instruments
11  *      Brandon Streiff <brandon.streiff@ni.com>
12  */
13
14 #include <linux/bitfield.h>
15
16 #include "global2.h"
17
18 /* Offset 0x16: AVB Command Register
19  * Offset 0x17: AVB Data Register
20  *
21  * There are two different versions of this register interface:
22  *    "6352": 3-bit "op" field, 4-bit "port" field.
23  *    "6390": 2-bit "op" field, 5-bit "port" field.
24  *
25  * The "op" codes are different between the two, as well as the special
26  * port fields for global PTP and TAI configuration.
27  */
28
29 /* mv88e6xxx_g2_avb_read -- Read one or multiple 16-bit words.
30  * The hardware supports snapshotting up to four contiguous registers.
31  */
32 static int mv88e6xxx_g2_avb_wait(struct mv88e6xxx_chip *chip)
33 {
34         int bit = __bf_shf(MV88E6352_G2_AVB_CMD_BUSY);
35
36         return mv88e6xxx_g2_wait_bit(chip, MV88E6352_G2_AVB_CMD, bit, 0);
37 }
38
39 static int mv88e6xxx_g2_avb_read(struct mv88e6xxx_chip *chip, u16 readop,
40                                  u16 *data, int len)
41 {
42         int err;
43         int i;
44
45         err = mv88e6xxx_g2_avb_wait(chip);
46         if (err)
47                 return err;
48
49         /* Hardware can only snapshot four words. */
50         if (len > 4)
51                 return -E2BIG;
52
53         err = mv88e6xxx_g2_write(chip, MV88E6352_G2_AVB_CMD,
54                                  MV88E6352_G2_AVB_CMD_BUSY | readop);
55         if (err)
56                 return err;
57
58         err = mv88e6xxx_g2_avb_wait(chip);
59         if (err)
60                 return err;
61
62         for (i = 0; i < len; ++i) {
63                 err = mv88e6xxx_g2_read(chip, MV88E6352_G2_AVB_DATA,
64                                         &data[i]);
65                 if (err)
66                         return err;
67         }
68
69         return 0;
70 }
71
72 /* mv88e6xxx_g2_avb_write -- Write one 16-bit word. */
73 static int mv88e6xxx_g2_avb_write(struct mv88e6xxx_chip *chip, u16 writeop,
74                                   u16 data)
75 {
76         int err;
77
78         err = mv88e6xxx_g2_avb_wait(chip);
79         if (err)
80                 return err;
81
82         err = mv88e6xxx_g2_write(chip, MV88E6352_G2_AVB_DATA, data);
83         if (err)
84                 return err;
85
86         err = mv88e6xxx_g2_write(chip, MV88E6352_G2_AVB_CMD,
87                                  MV88E6352_G2_AVB_CMD_BUSY | writeop);
88
89         return mv88e6xxx_g2_avb_wait(chip);
90 }
91
92 static int mv88e6352_g2_avb_port_ptp_read(struct mv88e6xxx_chip *chip,
93                                           int port, int addr, u16 *data,
94                                           int len)
95 {
96         u16 readop = (len == 1 ? MV88E6352_G2_AVB_CMD_OP_READ :
97                                  MV88E6352_G2_AVB_CMD_OP_READ_INCR) |
98                      (port << 8) | (MV88E6352_G2_AVB_CMD_BLOCK_PTP << 5) |
99                      addr;
100
101         return mv88e6xxx_g2_avb_read(chip, readop, data, len);
102 }
103
104 static int mv88e6352_g2_avb_port_ptp_write(struct mv88e6xxx_chip *chip,
105                                            int port, int addr, u16 data)
106 {
107         u16 writeop = MV88E6352_G2_AVB_CMD_OP_WRITE | (port << 8) |
108                       (MV88E6352_G2_AVB_CMD_BLOCK_PTP << 5) | addr;
109
110         return mv88e6xxx_g2_avb_write(chip, writeop, data);
111 }
112
113 static int mv88e6352_g2_avb_ptp_read(struct mv88e6xxx_chip *chip, int addr,
114                                      u16 *data, int len)
115 {
116         return mv88e6352_g2_avb_port_ptp_read(chip,
117                                         MV88E6352_G2_AVB_CMD_PORT_PTPGLOBAL,
118                                         addr, data, len);
119 }
120
121 static int mv88e6352_g2_avb_ptp_write(struct mv88e6xxx_chip *chip, int addr,
122                                       u16 data)
123 {
124         return mv88e6352_g2_avb_port_ptp_write(chip,
125                                         MV88E6352_G2_AVB_CMD_PORT_PTPGLOBAL,
126                                         addr, data);
127 }
128
129 static int mv88e6352_g2_avb_tai_read(struct mv88e6xxx_chip *chip, int addr,
130                                      u16 *data, int len)
131 {
132         return mv88e6352_g2_avb_port_ptp_read(chip,
133                                         MV88E6352_G2_AVB_CMD_PORT_TAIGLOBAL,
134                                         addr, data, len);
135 }
136
137 static int mv88e6352_g2_avb_tai_write(struct mv88e6xxx_chip *chip, int addr,
138                                       u16 data)
139 {
140         return mv88e6352_g2_avb_port_ptp_write(chip,
141                                         MV88E6352_G2_AVB_CMD_PORT_TAIGLOBAL,
142                                         addr, data);
143 }
144
145 const struct mv88e6xxx_avb_ops mv88e6352_avb_ops = {
146         .port_ptp_read          = mv88e6352_g2_avb_port_ptp_read,
147         .port_ptp_write         = mv88e6352_g2_avb_port_ptp_write,
148         .ptp_read               = mv88e6352_g2_avb_ptp_read,
149         .ptp_write              = mv88e6352_g2_avb_ptp_write,
150         .tai_read               = mv88e6352_g2_avb_tai_read,
151         .tai_write              = mv88e6352_g2_avb_tai_write,
152 };
153
154 static int mv88e6165_g2_avb_tai_read(struct mv88e6xxx_chip *chip, int addr,
155                                      u16 *data, int len)
156 {
157         return mv88e6352_g2_avb_port_ptp_read(chip,
158                                         MV88E6165_G2_AVB_CMD_PORT_PTPGLOBAL,
159                                         addr, data, len);
160 }
161
162 static int mv88e6165_g2_avb_tai_write(struct mv88e6xxx_chip *chip, int addr,
163                                       u16 data)
164 {
165         return mv88e6352_g2_avb_port_ptp_write(chip,
166                                         MV88E6165_G2_AVB_CMD_PORT_PTPGLOBAL,
167                                         addr, data);
168 }
169
170 const struct mv88e6xxx_avb_ops mv88e6165_avb_ops = {
171         .port_ptp_read          = mv88e6352_g2_avb_port_ptp_read,
172         .port_ptp_write         = mv88e6352_g2_avb_port_ptp_write,
173         .ptp_read               = mv88e6352_g2_avb_ptp_read,
174         .ptp_write              = mv88e6352_g2_avb_ptp_write,
175         .tai_read               = mv88e6165_g2_avb_tai_read,
176         .tai_write              = mv88e6165_g2_avb_tai_write,
177 };
178
179 static int mv88e6390_g2_avb_port_ptp_read(struct mv88e6xxx_chip *chip,
180                                           int port, int addr, u16 *data,
181                                           int len)
182 {
183         u16 readop = (len == 1 ? MV88E6390_G2_AVB_CMD_OP_READ :
184                                  MV88E6390_G2_AVB_CMD_OP_READ_INCR) |
185                      (port << 8) | (MV88E6352_G2_AVB_CMD_BLOCK_PTP << 5) |
186                      addr;
187
188         return mv88e6xxx_g2_avb_read(chip, readop, data, len);
189 }
190
191 static int mv88e6390_g2_avb_port_ptp_write(struct mv88e6xxx_chip *chip,
192                                            int port, int addr, u16 data)
193 {
194         u16 writeop = MV88E6390_G2_AVB_CMD_OP_WRITE | (port << 8) |
195                       (MV88E6352_G2_AVB_CMD_BLOCK_PTP << 5) | addr;
196
197         return mv88e6xxx_g2_avb_write(chip, writeop, data);
198 }
199
200 static int mv88e6390_g2_avb_ptp_read(struct mv88e6xxx_chip *chip, int addr,
201                                      u16 *data, int len)
202 {
203         return mv88e6390_g2_avb_port_ptp_read(chip,
204                                         MV88E6390_G2_AVB_CMD_PORT_PTPGLOBAL,
205                                         addr, data, len);
206 }
207
208 static int mv88e6390_g2_avb_ptp_write(struct mv88e6xxx_chip *chip, int addr,
209                                       u16 data)
210 {
211         return mv88e6390_g2_avb_port_ptp_write(chip,
212                                         MV88E6390_G2_AVB_CMD_PORT_PTPGLOBAL,
213                                         addr, data);
214 }
215
216 static int mv88e6390_g2_avb_tai_read(struct mv88e6xxx_chip *chip, int addr,
217                                      u16 *data, int len)
218 {
219         return mv88e6390_g2_avb_port_ptp_read(chip,
220                                         MV88E6390_G2_AVB_CMD_PORT_TAIGLOBAL,
221                                         addr, data, len);
222 }
223
224 static int mv88e6390_g2_avb_tai_write(struct mv88e6xxx_chip *chip, int addr,
225                                       u16 data)
226 {
227         return mv88e6390_g2_avb_port_ptp_write(chip,
228                                         MV88E6390_G2_AVB_CMD_PORT_TAIGLOBAL,
229                                         addr, data);
230 }
231
232 const struct mv88e6xxx_avb_ops mv88e6390_avb_ops = {
233         .port_ptp_read          = mv88e6390_g2_avb_port_ptp_read,
234         .port_ptp_write         = mv88e6390_g2_avb_port_ptp_write,
235         .ptp_read               = mv88e6390_g2_avb_ptp_read,
236         .ptp_write              = mv88e6390_g2_avb_ptp_write,
237         .tai_read               = mv88e6390_g2_avb_tai_read,
238         .tai_write              = mv88e6390_g2_avb_tai_write,
239 };