]>
Commit | Line | Data |
---|---|---|
d2912cb1 | 1 | // SPDX-License-Identifier: GPL-2.0-only |
1edb9ca6 SR |
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> | |
1edb9ca6 SR |
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 | ||
acc18c14 G |
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 | ||
1edb9ca6 SR |
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 | { | |
acc18c14 G |
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; | |
1edb9ca6 SR |
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 | ||
4f6ed914 DC |
93 | high_word = (addr[5] << 8) | (addr[4]); |
94 | low_word = (addr[3] << 24) | (addr[2] << 16) | | |
95 | (addr[1] << 8) | (addr[0]); | |
1edb9ca6 SR |
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 | ||
325b94f7 BA |
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 | ||
acc18c14 G |
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 | ||
8f7807ae VP |
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 | ||
7baea6ef | 256 | static const struct sxgbe_core_ops core_ops = { |
1edb9ca6 SR |
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, | |
acc18c14 G |
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, | |
8f7807ae VP |
272 | .enable_rx_csum = sxgbe_enable_rx_csum, |
273 | .disable_rx_csum = sxgbe_disable_rx_csum, | |
325b94f7 BA |
274 | .enable_rxqueue = sxgbe_core_enable_rxqueue, |
275 | .disable_rxqueue = sxgbe_core_disable_rxqueue, | |
1edb9ca6 SR |
276 | }; |
277 | ||
278 | const struct sxgbe_core_ops *sxgbe_get_core_ops(void) | |
279 | { | |
280 | return &core_ops; | |
281 | } |