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