1 // SPDX-License-Identifier: GPL-2.0-only
2 /* 10G controller driver for Samsung SoCs
3  *
4  * Copyright (C) 2013 Samsung Electronics Co., Ltd.
5  *		http://www.samsung.com
6  *
7  * Author: Siva Reddy Kallam <siva.kallam@samsung.com>
8  */
9 
10 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
11 
12 #include <linux/export.h>
13 #include <linux/io.h>
14 #include <linux/netdevice.h>
15 #include <linux/phy.h>
16 
17 #include "sxgbe_common.h"
18 #include "sxgbe_reg.h"
19 
20 /* MAC core initialization */
21 static void sxgbe_core_init(void __iomem *ioaddr)
22 {
23 	u32 regval;
24 
25 	/* TX configuration */
26 	regval = readl(ioaddr + SXGBE_CORE_TX_CONFIG_REG);
27 	/* Other configurable parameters IFP, IPG, ISR, ISM
28 	 * needs to be set if needed
29 	 */
30 	regval |= SXGBE_TX_JABBER_DISABLE;
31 	writel(regval, ioaddr + SXGBE_CORE_TX_CONFIG_REG);
32 
33 	/* RX configuration */
34 	regval = readl(ioaddr + SXGBE_CORE_RX_CONFIG_REG);
35 	/* Other configurable parameters CST, SPEN, USP, GPSLCE
36 	 * WD, LM, S2KP, HDSMS, GPSL, ELEN, ARPEN needs to be
37 	 * set if needed
38 	 */
39 	regval |= SXGBE_RX_JUMBPKT_ENABLE | SXGBE_RX_ACS_ENABLE;
40 	writel(regval, ioaddr + SXGBE_CORE_RX_CONFIG_REG);
41 }
42 
43 /* Dump MAC registers */
44 static void sxgbe_core_dump_regs(void __iomem *ioaddr)
45 {
46 }
47 
48 static int sxgbe_get_lpi_status(void __iomem *ioaddr, const u32 irq_status)
49 {
50 	int status = 0;
51 	int lpi_status;
52 
53 	/* Reading this register shall clear all the LPI status bits */
54 	lpi_status = readl(ioaddr + SXGBE_CORE_LPI_CTRL_STATUS);
55 
56 	if (lpi_status & LPI_CTRL_STATUS_TLPIEN)
57 		status |= TX_ENTRY_LPI_MODE;
58 	if (lpi_status & LPI_CTRL_STATUS_TLPIEX)
59 		status |= TX_EXIT_LPI_MODE;
60 	if (lpi_status & LPI_CTRL_STATUS_RLPIEN)
61 		status |= RX_ENTRY_LPI_MODE;
62 	if (lpi_status & LPI_CTRL_STATUS_RLPIEX)
63 		status |= RX_EXIT_LPI_MODE;
64 
65 	return status;
66 }
67 
68 /* Handle extra events on specific interrupts hw dependent */
69 static int sxgbe_core_host_irq_status(void __iomem *ioaddr,
70 				      struct sxgbe_extra_stats *x)
71 {
72 	int irq_status, status = 0;
73 
74 	irq_status = readl(ioaddr + SXGBE_CORE_INT_STATUS_REG);
75 
76 	if (unlikely(irq_status & LPI_INT_STATUS))
77 		status |= sxgbe_get_lpi_status(ioaddr, irq_status);
78 
79 	return status;
80 }
81 
82 /* Set power management mode (e.g. magic frame) */
83 static void sxgbe_core_pmt(void __iomem *ioaddr, unsigned long mode)
84 {
85 }
86 
87 /* Set/Get Unicast MAC addresses */
88 static void sxgbe_core_set_umac_addr(void __iomem *ioaddr, unsigned char *addr,
89 				     unsigned int reg_n)
90 {
91 	u32 high_word, low_word;
92 
93 	high_word = (addr[5] << 8) | (addr[4]);
94 	low_word = (addr[3] << 24) | (addr[2] << 16) |
95 		   (addr[1] << 8) | (addr[0]);
96 	writel(high_word, ioaddr + SXGBE_CORE_ADD_HIGHOFFSET(reg_n));
97 	writel(low_word, ioaddr + SXGBE_CORE_ADD_LOWOFFSET(reg_n));
98 }
99 
100 static void sxgbe_core_get_umac_addr(void __iomem *ioaddr, unsigned char *addr,
101 				     unsigned int reg_n)
102 {
103 	u32 high_word, low_word;
104 
105 	high_word = readl(ioaddr + SXGBE_CORE_ADD_HIGHOFFSET(reg_n));
106 	low_word = readl(ioaddr + SXGBE_CORE_ADD_LOWOFFSET(reg_n));
107 
108 	/* extract and assign address */
109 	addr[5] = (high_word & 0x0000FF00) >> 8;
110 	addr[4] = (high_word & 0x000000FF);
111 	addr[3] = (low_word & 0xFF000000) >> 24;
112 	addr[2] = (low_word & 0x00FF0000) >> 16;
113 	addr[1] = (low_word & 0x0000FF00) >> 8;
114 	addr[0] = (low_word & 0x000000FF);
115 }
116 
117 static void sxgbe_enable_tx(void __iomem *ioaddr, bool enable)
118 {
119 	u32 tx_config;
120 
121 	tx_config = readl(ioaddr + SXGBE_CORE_TX_CONFIG_REG);
122 	tx_config &= ~SXGBE_TX_ENABLE;
123 
124 	if (enable)
125 		tx_config |= SXGBE_TX_ENABLE;
126 	writel(tx_config, ioaddr + SXGBE_CORE_TX_CONFIG_REG);
127 }
128 
129 static void sxgbe_enable_rx(void __iomem *ioaddr, bool enable)
130 {
131 	u32 rx_config;
132 
133 	rx_config = readl(ioaddr + SXGBE_CORE_RX_CONFIG_REG);
134 	rx_config &= ~SXGBE_RX_ENABLE;
135 
136 	if (enable)
137 		rx_config |= SXGBE_RX_ENABLE;
138 	writel(rx_config, ioaddr + SXGBE_CORE_RX_CONFIG_REG);
139 }
140 
141 static int sxgbe_get_controller_version(void __iomem *ioaddr)
142 {
143 	return readl(ioaddr + SXGBE_CORE_VERSION_REG);
144 }
145 
146 /* If supported then get the optional core features */
147 static unsigned int sxgbe_get_hw_feature(void __iomem *ioaddr,
148 					 unsigned char feature_index)
149 {
150 	return readl(ioaddr + (SXGBE_CORE_HW_FEA_REG(feature_index)));
151 }
152 
153 static void sxgbe_core_set_speed(void __iomem *ioaddr, unsigned char speed)
154 {
155 	u32 tx_cfg = readl(ioaddr + SXGBE_CORE_TX_CONFIG_REG);
156 
157 	/* clear the speed bits */
158 	tx_cfg &= ~0x60000000;
159 	tx_cfg |= (speed << SXGBE_SPEED_LSHIFT);
160 
161 	/* set the speed */
162 	writel(tx_cfg, ioaddr + SXGBE_CORE_TX_CONFIG_REG);
163 }
164 
165 static void sxgbe_core_enable_rxqueue(void __iomem *ioaddr, int queue_num)
166 {
167 	u32 reg_val;
168 
169 	reg_val = readl(ioaddr + SXGBE_CORE_RX_CTL0_REG);
170 	reg_val &= ~(SXGBE_CORE_RXQ_ENABLE_MASK << queue_num);
171 	reg_val |= SXGBE_CORE_RXQ_ENABLE;
172 	writel(reg_val, ioaddr + SXGBE_CORE_RX_CTL0_REG);
173 }
174 
175 static void sxgbe_core_disable_rxqueue(void __iomem *ioaddr, int queue_num)
176 {
177 	u32 reg_val;
178 
179 	reg_val = readl(ioaddr + SXGBE_CORE_RX_CTL0_REG);
180 	reg_val &= ~(SXGBE_CORE_RXQ_ENABLE_MASK << queue_num);
181 	reg_val |= SXGBE_CORE_RXQ_DISABLE;
182 	writel(reg_val, ioaddr + SXGBE_CORE_RX_CTL0_REG);
183 }
184 
185 static void  sxgbe_set_eee_mode(void __iomem *ioaddr)
186 {
187 	u32 ctrl;
188 
189 	/* Enable the LPI mode for transmit path with Tx automate bit set.
190 	 * When Tx Automate bit is set, MAC internally handles the entry
191 	 * to LPI mode after all outstanding and pending packets are
192 	 * transmitted.
193 	 */
194 	ctrl = readl(ioaddr + SXGBE_CORE_LPI_CTRL_STATUS);
195 	ctrl |= LPI_CTRL_STATUS_LPIEN | LPI_CTRL_STATUS_TXA;
196 	writel(ctrl, ioaddr + SXGBE_CORE_LPI_CTRL_STATUS);
197 }
198 
199 static void  sxgbe_reset_eee_mode(void __iomem *ioaddr)
200 {
201 	u32 ctrl;
202 
203 	ctrl = readl(ioaddr + SXGBE_CORE_LPI_CTRL_STATUS);
204 	ctrl &= ~(LPI_CTRL_STATUS_LPIEN | LPI_CTRL_STATUS_TXA);
205 	writel(ctrl, ioaddr + SXGBE_CORE_LPI_CTRL_STATUS);
206 }
207 
208 static void  sxgbe_set_eee_pls(void __iomem *ioaddr, const int link)
209 {
210 	u32 ctrl;
211 
212 	ctrl = readl(ioaddr + SXGBE_CORE_LPI_CTRL_STATUS);
213 
214 	/* If the PHY link status is UP then set PLS */
215 	if (link)
216 		ctrl |= LPI_CTRL_STATUS_PLS;
217 	else
218 		ctrl &= ~LPI_CTRL_STATUS_PLS;
219 
220 	writel(ctrl, ioaddr + SXGBE_CORE_LPI_CTRL_STATUS);
221 }
222 
223 static void  sxgbe_set_eee_timer(void __iomem *ioaddr,
224 				 const int ls, const int tw)
225 {
226 	int value = ((tw & 0xffff)) | ((ls & 0x7ff) << 16);
227 
228 	/* Program the timers in the LPI timer control register:
229 	 * LS: minimum time (ms) for which the link
230 	 *  status from PHY should be ok before transmitting
231 	 *  the LPI pattern.
232 	 * TW: minimum time (us) for which the core waits
233 	 *  after it has stopped transmitting the LPI pattern.
234 	 */
235 	writel(value, ioaddr + SXGBE_CORE_LPI_TIMER_CTRL);
236 }
237 
238 static void sxgbe_enable_rx_csum(void __iomem *ioaddr)
239 {
240 	u32 ctrl;
241 
242 	ctrl = readl(ioaddr + SXGBE_CORE_RX_CONFIG_REG);
243 	ctrl |= SXGBE_RX_CSUMOFFLOAD_ENABLE;
244 	writel(ctrl, ioaddr + SXGBE_CORE_RX_CONFIG_REG);
245 }
246 
247 static void sxgbe_disable_rx_csum(void __iomem *ioaddr)
248 {
249 	u32 ctrl;
250 
251 	ctrl = readl(ioaddr + SXGBE_CORE_RX_CONFIG_REG);
252 	ctrl &= ~SXGBE_RX_CSUMOFFLOAD_ENABLE;
253 	writel(ctrl, ioaddr + SXGBE_CORE_RX_CONFIG_REG);
254 }
255 
256 static const struct sxgbe_core_ops core_ops = {
257 	.core_init		= sxgbe_core_init,
258 	.dump_regs		= sxgbe_core_dump_regs,
259 	.host_irq_status	= sxgbe_core_host_irq_status,
260 	.pmt			= sxgbe_core_pmt,
261 	.set_umac_addr		= sxgbe_core_set_umac_addr,
262 	.get_umac_addr		= sxgbe_core_get_umac_addr,
263 	.enable_rx		= sxgbe_enable_rx,
264 	.enable_tx		= sxgbe_enable_tx,
265 	.get_controller_version	= sxgbe_get_controller_version,
266 	.get_hw_feature		= sxgbe_get_hw_feature,
267 	.set_speed		= sxgbe_core_set_speed,
268 	.set_eee_mode		= sxgbe_set_eee_mode,
269 	.reset_eee_mode		= sxgbe_reset_eee_mode,
270 	.set_eee_timer		= sxgbe_set_eee_timer,
271 	.set_eee_pls		= sxgbe_set_eee_pls,
272 	.enable_rx_csum		= sxgbe_enable_rx_csum,
273 	.disable_rx_csum	= sxgbe_disable_rx_csum,
274 	.enable_rxqueue		= sxgbe_core_enable_rxqueue,
275 	.disable_rxqueue	= sxgbe_core_disable_rxqueue,
276 };
277 
278 const struct sxgbe_core_ops *sxgbe_get_core_ops(void)
279 {
280 	return &core_ops;
281 }
282