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 "global2.h"
15 
16 /* Offset 0x16: AVB Command Register
17  * Offset 0x17: AVB Data Register
18  *
19  * There are two different versions of this register interface:
20  *    "6352": 3-bit "op" field, 4-bit "port" field.
21  *    "6390": 2-bit "op" field, 5-bit "port" field.
22  *
23  * The "op" codes are different between the two, as well as the special
24  * port fields for global PTP and TAI configuration.
25  */
26 
27 /* mv88e6xxx_g2_avb_read -- Read one or multiple 16-bit words.
28  * The hardware supports snapshotting up to four contiguous registers.
29  */
30 static int mv88e6xxx_g2_avb_read(struct mv88e6xxx_chip *chip, u16 readop,
31 				 u16 *data, int len)
32 {
33 	int err;
34 	int i;
35 
36 	/* Hardware can only snapshot four words. */
37 	if (len > 4)
38 		return -E2BIG;
39 
40 	err = mv88e6xxx_g2_update(chip, MV88E6352_G2_AVB_CMD, readop);
41 	if (err)
42 		return err;
43 
44 	for (i = 0; i < len; ++i) {
45 		err = mv88e6xxx_g2_read(chip, MV88E6352_G2_AVB_DATA,
46 					&data[i]);
47 		if (err)
48 			return err;
49 	}
50 
51 	return 0;
52 }
53 
54 /* mv88e6xxx_g2_avb_write -- Write one 16-bit word. */
55 static int mv88e6xxx_g2_avb_write(struct mv88e6xxx_chip *chip, u16 writeop,
56 				  u16 data)
57 {
58 	int err;
59 
60 	err = mv88e6xxx_g2_write(chip, MV88E6352_G2_AVB_DATA, data);
61 	if (err)
62 		return err;
63 
64 	return mv88e6xxx_g2_update(chip, MV88E6352_G2_AVB_CMD, writeop);
65 }
66 
67 static int mv88e6352_g2_avb_port_ptp_read(struct mv88e6xxx_chip *chip,
68 					  int port, int addr, u16 *data,
69 					  int len)
70 {
71 	u16 readop = (len == 1 ? MV88E6352_G2_AVB_CMD_OP_READ :
72 				 MV88E6352_G2_AVB_CMD_OP_READ_INCR) |
73 		     (port << 8) | (MV88E6352_G2_AVB_CMD_BLOCK_PTP << 5) |
74 		     addr;
75 
76 	return mv88e6xxx_g2_avb_read(chip, readop, data, len);
77 }
78 
79 static int mv88e6352_g2_avb_port_ptp_write(struct mv88e6xxx_chip *chip,
80 					   int port, int addr, u16 data)
81 {
82 	u16 writeop = MV88E6352_G2_AVB_CMD_OP_WRITE | (port << 8) |
83 		      (MV88E6352_G2_AVB_CMD_BLOCK_PTP << 5) | addr;
84 
85 	return mv88e6xxx_g2_avb_write(chip, writeop, data);
86 }
87 
88 static int mv88e6352_g2_avb_ptp_read(struct mv88e6xxx_chip *chip, int addr,
89 				     u16 *data, int len)
90 {
91 	return mv88e6352_g2_avb_port_ptp_read(chip,
92 					MV88E6352_G2_AVB_CMD_PORT_PTPGLOBAL,
93 					addr, data, len);
94 }
95 
96 static int mv88e6352_g2_avb_ptp_write(struct mv88e6xxx_chip *chip, int addr,
97 				      u16 data)
98 {
99 	return mv88e6352_g2_avb_port_ptp_write(chip,
100 					MV88E6352_G2_AVB_CMD_PORT_PTPGLOBAL,
101 					addr, data);
102 }
103 
104 static int mv88e6352_g2_avb_tai_read(struct mv88e6xxx_chip *chip, int addr,
105 				     u16 *data, int len)
106 {
107 	return mv88e6352_g2_avb_port_ptp_read(chip,
108 					MV88E6352_G2_AVB_CMD_PORT_TAIGLOBAL,
109 					addr, data, len);
110 }
111 
112 static int mv88e6352_g2_avb_tai_write(struct mv88e6xxx_chip *chip, int addr,
113 				      u16 data)
114 {
115 	return mv88e6352_g2_avb_port_ptp_write(chip,
116 					MV88E6352_G2_AVB_CMD_PORT_TAIGLOBAL,
117 					addr, data);
118 }
119 
120 const struct mv88e6xxx_avb_ops mv88e6352_avb_ops = {
121 	.port_ptp_read		= mv88e6352_g2_avb_port_ptp_read,
122 	.port_ptp_write		= mv88e6352_g2_avb_port_ptp_write,
123 	.ptp_read		= mv88e6352_g2_avb_ptp_read,
124 	.ptp_write		= mv88e6352_g2_avb_ptp_write,
125 	.tai_read		= mv88e6352_g2_avb_tai_read,
126 	.tai_write		= mv88e6352_g2_avb_tai_write,
127 };
128 
129 static int mv88e6165_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 					MV88E6165_G2_AVB_CMD_PORT_PTPGLOBAL,
134 					addr, data, len);
135 }
136 
137 static int mv88e6165_g2_avb_tai_write(struct mv88e6xxx_chip *chip, int addr,
138 				      u16 data)
139 {
140 	return mv88e6352_g2_avb_port_ptp_write(chip,
141 					MV88E6165_G2_AVB_CMD_PORT_PTPGLOBAL,
142 					addr, data);
143 }
144 
145 const struct mv88e6xxx_avb_ops mv88e6165_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		= mv88e6165_g2_avb_tai_read,
151 	.tai_write		= mv88e6165_g2_avb_tai_write,
152 };
153 
154 static int mv88e6390_g2_avb_port_ptp_read(struct mv88e6xxx_chip *chip,
155 					  int port, int addr, u16 *data,
156 					  int len)
157 {
158 	u16 readop = (len == 1 ? MV88E6390_G2_AVB_CMD_OP_READ :
159 				 MV88E6390_G2_AVB_CMD_OP_READ_INCR) |
160 		     (port << 8) | (MV88E6352_G2_AVB_CMD_BLOCK_PTP << 5) |
161 		     addr;
162 
163 	return mv88e6xxx_g2_avb_read(chip, readop, data, len);
164 }
165 
166 static int mv88e6390_g2_avb_port_ptp_write(struct mv88e6xxx_chip *chip,
167 					   int port, int addr, u16 data)
168 {
169 	u16 writeop = MV88E6390_G2_AVB_CMD_OP_WRITE | (port << 8) |
170 		      (MV88E6352_G2_AVB_CMD_BLOCK_PTP << 5) | addr;
171 
172 	return mv88e6xxx_g2_avb_write(chip, writeop, data);
173 }
174 
175 static int mv88e6390_g2_avb_ptp_read(struct mv88e6xxx_chip *chip, int addr,
176 				     u16 *data, int len)
177 {
178 	return mv88e6390_g2_avb_port_ptp_read(chip,
179 					MV88E6390_G2_AVB_CMD_PORT_PTPGLOBAL,
180 					addr, data, len);
181 }
182 
183 static int mv88e6390_g2_avb_ptp_write(struct mv88e6xxx_chip *chip, int addr,
184 				      u16 data)
185 {
186 	return mv88e6390_g2_avb_port_ptp_write(chip,
187 					MV88E6390_G2_AVB_CMD_PORT_PTPGLOBAL,
188 					addr, data);
189 }
190 
191 static int mv88e6390_g2_avb_tai_read(struct mv88e6xxx_chip *chip, int addr,
192 				     u16 *data, int len)
193 {
194 	return mv88e6390_g2_avb_port_ptp_read(chip,
195 					MV88E6390_G2_AVB_CMD_PORT_TAIGLOBAL,
196 					addr, data, len);
197 }
198 
199 static int mv88e6390_g2_avb_tai_write(struct mv88e6xxx_chip *chip, int addr,
200 				      u16 data)
201 {
202 	return mv88e6390_g2_avb_port_ptp_write(chip,
203 					MV88E6390_G2_AVB_CMD_PORT_TAIGLOBAL,
204 					addr, data);
205 }
206 
207 const struct mv88e6xxx_avb_ops mv88e6390_avb_ops = {
208 	.port_ptp_read		= mv88e6390_g2_avb_port_ptp_read,
209 	.port_ptp_write		= mv88e6390_g2_avb_port_ptp_write,
210 	.ptp_read		= mv88e6390_g2_avb_ptp_read,
211 	.ptp_write		= mv88e6390_g2_avb_ptp_write,
212 	.tai_read		= mv88e6390_g2_avb_tai_read,
213 	.tai_write		= mv88e6390_g2_avb_tai_write,
214 };
215