Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

Merge branch 'hisilicon-mdio-femac'

Dongpo Li says:

====================
Add Hisilicon MDIO bus driver and FEMAC driver

This patch set adds a Hisilicon MDIO bus driver and
a Fast Ethernet MAC(FEMAC) driver.
We also abstract a general interface "of_phy_get_and_connect"
for PHY connect. User will have no bother with getting
"phy-mode" and "phy-handle" any more.

Changes in v1:
- Pass private data structure instead of struct mii_bus
in MDIO read and write operation.
- Return the error which devm_clk_get() gives when MDIO probe.
- Leave the clock unprepared and disabled on error when MDIO probe.
- Abstract a general interface "of_phy_get_and_connect" for PHY connect.
- Remove the "_reset" suffixes in "reset-names" property.
- Enable tx per-packet interrupt when tx fifo full.
- Remove pointless compatible and add SoC specific compatible.
- Declare only one clock in MAC dts documentation.
- Add standard unit suffixes for "phy-reset-delays".
- Use a smaller NAPI poll weight 16 for our Fast Ethernet MAC.
- Use phy_ethtool_{get|set}_link_ksettings for ethtool ops.
- Use phydev from struct net_device in MAC driver.
====================

Signed-off-by: David S. Miller <davem@davemloft.net>

+1301
+22
Documentation/devicetree/bindings/net/hisilicon-femac-mdio.txt
··· 1 + Hisilicon Fast Ethernet MDIO Controller interface 2 + 3 + Required properties: 4 + - compatible: should be "hisilicon,hisi-femac-mdio". 5 + - reg: address and length of the register set for the device. 6 + - clocks: A phandle to the reference clock for this device. 7 + 8 + - PHY subnode: inherits from phy binding [1] 9 + [1] Documentation/devicetree/bindings/net/phy.txt 10 + 11 + Example: 12 + mdio: mdio@10091100 { 13 + compatible = "hisilicon,hisi-femac-mdio"; 14 + reg = <0x10091100 0x10>; 15 + clocks = <&crg HI3516CV300_MDIO_CLK>; 16 + #address-cells = <1>; 17 + #size-cells = <0>; 18 + 19 + phy0: phy@1 { 20 + reg = <1>; 21 + }; 22 + };
+39
Documentation/devicetree/bindings/net/hisilicon-femac.txt
··· 1 + Hisilicon Fast Ethernet MAC controller 2 + 3 + Required properties: 4 + - compatible: should contain one of the following version strings: 5 + * "hisilicon,hisi-femac-v1" 6 + * "hisilicon,hisi-femac-v2" 7 + and the soc string "hisilicon,hi3516cv300-femac". 8 + - reg: specifies base physical address(s) and size of the device registers. 9 + The first region is the MAC core register base and size. 10 + The second region is the global MAC control register. 11 + - interrupts: should contain the MAC interrupt. 12 + - clocks: A phandle to the MAC main clock. 13 + - resets: should contain the phandle to the MAC reset signal(required) and 14 + the PHY reset signal(optional). 15 + - reset-names: should contain the reset signal name "mac"(required) 16 + and "phy"(optional). 17 + - mac-address: see ethernet.txt [1]. 18 + - phy-mode: see ethernet.txt [1]. 19 + - phy-handle: see ethernet.txt [1]. 20 + - hisilicon,phy-reset-delays-us: triplet of delays if PHY reset signal given. 21 + The 1st cell is reset pre-delay in micro seconds. 22 + The 2nd cell is reset pulse in micro seconds. 23 + The 3rd cell is reset post-delay in micro seconds. 24 + 25 + [1] Documentation/devicetree/bindings/net/ethernet.txt 26 + 27 + Example: 28 + hisi_femac: ethernet@10090000 { 29 + compatible = "hisilicon,hi3516cv300-femac","hisilicon,hisi-femac-v2"; 30 + reg = <0x10090000 0x1000>,<0x10091300 0x200>; 31 + interrupts = <12>; 32 + clocks = <&crg HI3518EV200_ETH_CLK>; 33 + resets = <&crg 0xec 0>,<&crg 0xec 3>; 34 + reset-names = "mac","phy"; 35 + mac-address = [00 00 00 00 00 00]; 36 + phy-mode = "mii"; 37 + phy-handle = <&phy0>; 38 + hisilicon,phy-reset-delays-us = <10000 20000 20000>; 39 + };
+12
drivers/net/ethernet/hisilicon/Kconfig
··· 23 23 help 24 24 This selects the hix5hd2 mac family network device. 25 25 26 + config HISI_FEMAC 27 + tristate "Hisilicon Fast Ethernet MAC device support" 28 + depends on HAS_IOMEM 29 + select PHYLIB 30 + select RESET_CONTROLLER 31 + help 32 + This selects the Hisilicon Fast Ethernet MAC device(FEMAC). 33 + The FEMAC receives and transmits data over Ethernet 34 + ports at 10/100 Mbps in full-duplex or half-duplex mode. 35 + The FEMAC exchanges data with the CPU, and supports 36 + the energy efficient Ethernet (EEE). 37 + 26 38 config HIP04_ETH 27 39 tristate "HISILICON P04 Ethernet support" 28 40 depends on HAS_IOMEM # For MFD_SYSCON
+1
drivers/net/ethernet/hisilicon/Makefile
··· 6 6 obj-$(CONFIG_HIP04_ETH) += hip04_eth.o 7 7 obj-$(CONFIG_HNS_MDIO) += hns_mdio.o 8 8 obj-$(CONFIG_HNS) += hns/ 9 + obj-$(CONFIG_HISI_FEMAC) += hisi_femac.o
+1007
drivers/net/ethernet/hisilicon/hisi_femac.c
··· 1 + /* 2 + * Hisilicon Fast Ethernet MAC Driver 3 + * 4 + * Copyright (c) 2016 HiSilicon Technologies Co., Ltd. 5 + * 6 + * This program is free software; you can redistribute it and/or modify 7 + * it under the terms of the GNU General Public License as published by 8 + * the Free Software Foundation; either version 2 of the License, or 9 + * (at your option) any later version. 10 + * 11 + * This program is distributed in the hope that it will be useful, 12 + * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 + * GNU General Public License for more details. 15 + * 16 + * You should have received a copy of the GNU General Public License 17 + * along with this program. If not, see <http://www.gnu.org/licenses/>. 18 + */ 19 + 20 + #include <linux/circ_buf.h> 21 + #include <linux/clk.h> 22 + #include <linux/etherdevice.h> 23 + #include <linux/interrupt.h> 24 + #include <linux/module.h> 25 + #include <linux/of_mdio.h> 26 + #include <linux/of_net.h> 27 + #include <linux/platform_device.h> 28 + #include <linux/reset.h> 29 + 30 + /* MAC control register list */ 31 + #define MAC_PORTSEL 0x0200 32 + #define MAC_PORTSEL_STAT_CPU BIT(0) 33 + #define MAC_PORTSEL_RMII BIT(1) 34 + #define MAC_PORTSET 0x0208 35 + #define MAC_PORTSET_DUPLEX_FULL BIT(0) 36 + #define MAC_PORTSET_LINKED BIT(1) 37 + #define MAC_PORTSET_SPEED_100M BIT(2) 38 + #define MAC_SET 0x0210 39 + #define MAX_FRAME_SIZE 1600 40 + #define MAX_FRAME_SIZE_MASK GENMASK(10, 0) 41 + #define BIT_PAUSE_EN BIT(18) 42 + #define RX_COALESCE_SET 0x0340 43 + #define RX_COALESCED_FRAME_OFFSET 24 44 + #define RX_COALESCED_FRAMES 8 45 + #define RX_COALESCED_TIMER 0x74 46 + #define QLEN_SET 0x0344 47 + #define RX_DEPTH_OFFSET 8 48 + #define MAX_HW_FIFO_DEPTH 64 49 + #define HW_TX_FIFO_DEPTH 12 50 + #define HW_RX_FIFO_DEPTH (MAX_HW_FIFO_DEPTH - HW_TX_FIFO_DEPTH) 51 + #define IQFRM_DES 0x0354 52 + #define RX_FRAME_LEN_MASK GENMASK(11, 0) 53 + #define IQ_ADDR 0x0358 54 + #define EQ_ADDR 0x0360 55 + #define EQFRM_LEN 0x0364 56 + #define ADDRQ_STAT 0x036C 57 + #define TX_CNT_INUSE_MASK GENMASK(5, 0) 58 + #define BIT_TX_READY BIT(24) 59 + #define BIT_RX_READY BIT(25) 60 + /* global control register list */ 61 + #define GLB_HOSTMAC_L32 0x0000 62 + #define GLB_HOSTMAC_H16 0x0004 63 + #define GLB_SOFT_RESET 0x0008 64 + #define SOFT_RESET_ALL BIT(0) 65 + #define GLB_FWCTRL 0x0010 66 + #define FWCTRL_VLAN_ENABLE BIT(0) 67 + #define FWCTRL_FW2CPU_ENA BIT(5) 68 + #define FWCTRL_FWALL2CPU BIT(7) 69 + #define GLB_MACTCTRL 0x0014 70 + #define MACTCTRL_UNI2CPU BIT(1) 71 + #define MACTCTRL_MULTI2CPU BIT(3) 72 + #define MACTCTRL_BROAD2CPU BIT(5) 73 + #define MACTCTRL_MACT_ENA BIT(7) 74 + #define GLB_IRQ_STAT 0x0030 75 + #define GLB_IRQ_ENA 0x0034 76 + #define IRQ_ENA_PORT0_MASK GENMASK(7, 0) 77 + #define IRQ_ENA_PORT0 BIT(18) 78 + #define IRQ_ENA_ALL BIT(19) 79 + #define GLB_IRQ_RAW 0x0038 80 + #define IRQ_INT_RX_RDY BIT(0) 81 + #define IRQ_INT_TX_PER_PACKET BIT(1) 82 + #define IRQ_INT_TX_FIFO_EMPTY BIT(6) 83 + #define IRQ_INT_MULTI_RXRDY BIT(7) 84 + #define DEF_INT_MASK (IRQ_INT_MULTI_RXRDY | \ 85 + IRQ_INT_TX_PER_PACKET | \ 86 + IRQ_INT_TX_FIFO_EMPTY) 87 + #define GLB_MAC_L32_BASE 0x0100 88 + #define GLB_MAC_H16_BASE 0x0104 89 + #define MACFLT_HI16_MASK GENMASK(15, 0) 90 + #define BIT_MACFLT_ENA BIT(17) 91 + #define BIT_MACFLT_FW2CPU BIT(21) 92 + #define GLB_MAC_H16(reg) (GLB_MAC_H16_BASE + ((reg) * 0x8)) 93 + #define GLB_MAC_L32(reg) (GLB_MAC_L32_BASE + ((reg) * 0x8)) 94 + #define MAX_MAC_FILTER_NUM 8 95 + #define MAX_UNICAST_ADDRESSES 2 96 + #define MAX_MULTICAST_ADDRESSES (MAX_MAC_FILTER_NUM - \ 97 + MAX_UNICAST_ADDRESSES) 98 + /* software tx and rx queue number, should be power of 2 */ 99 + #define TXQ_NUM 64 100 + #define RXQ_NUM 128 101 + #define FEMAC_POLL_WEIGHT 16 102 + 103 + #define PHY_RESET_DELAYS_PROPERTY "hisilicon,phy-reset-delays-us" 104 + 105 + enum phy_reset_delays { 106 + PRE_DELAY, 107 + PULSE, 108 + POST_DELAY, 109 + DELAYS_NUM, 110 + }; 111 + 112 + struct hisi_femac_queue { 113 + struct sk_buff **skb; 114 + dma_addr_t *dma_phys; 115 + int num; 116 + unsigned int head; 117 + unsigned int tail; 118 + }; 119 + 120 + struct hisi_femac_priv { 121 + void __iomem *port_base; 122 + void __iomem *glb_base; 123 + struct clk *clk; 124 + struct reset_control *mac_rst; 125 + struct reset_control *phy_rst; 126 + u32 phy_reset_delays[DELAYS_NUM]; 127 + u32 link_status; 128 + 129 + struct device *dev; 130 + struct net_device *ndev; 131 + 132 + struct hisi_femac_queue txq; 133 + struct hisi_femac_queue rxq; 134 + u32 tx_fifo_used_cnt; 135 + struct napi_struct napi; 136 + }; 137 + 138 + static void hisi_femac_irq_enable(struct hisi_femac_priv *priv, int irqs) 139 + { 140 + u32 val; 141 + 142 + val = readl(priv->glb_base + GLB_IRQ_ENA); 143 + writel(val | irqs, priv->glb_base + GLB_IRQ_ENA); 144 + } 145 + 146 + static void hisi_femac_irq_disable(struct hisi_femac_priv *priv, int irqs) 147 + { 148 + u32 val; 149 + 150 + val = readl(priv->glb_base + GLB_IRQ_ENA); 151 + writel(val & (~irqs), priv->glb_base + GLB_IRQ_ENA); 152 + } 153 + 154 + static void hisi_femac_tx_dma_unmap(struct hisi_femac_priv *priv, 155 + struct sk_buff *skb, unsigned int pos) 156 + { 157 + dma_addr_t dma_addr; 158 + 159 + dma_addr = priv->txq.dma_phys[pos]; 160 + dma_unmap_single(priv->dev, dma_addr, skb->len, DMA_TO_DEVICE); 161 + } 162 + 163 + static void hisi_femac_xmit_reclaim(struct net_device *dev) 164 + { 165 + struct sk_buff *skb; 166 + struct hisi_femac_priv *priv = netdev_priv(dev); 167 + struct hisi_femac_queue *txq = &priv->txq; 168 + unsigned int bytes_compl = 0, pkts_compl = 0; 169 + u32 val; 170 + 171 + netif_tx_lock(dev); 172 + 173 + val = readl(priv->port_base + ADDRQ_STAT) & TX_CNT_INUSE_MASK; 174 + while (val < priv->tx_fifo_used_cnt) { 175 + skb = txq->skb[txq->tail]; 176 + if (unlikely(!skb)) { 177 + netdev_err(dev, "xmitq_cnt_inuse=%d, tx_fifo_used=%d\n", 178 + val, priv->tx_fifo_used_cnt); 179 + break; 180 + } 181 + hisi_femac_tx_dma_unmap(priv, skb, txq->tail); 182 + pkts_compl++; 183 + bytes_compl += skb->len; 184 + dev_kfree_skb_any(skb); 185 + 186 + priv->tx_fifo_used_cnt--; 187 + 188 + val = readl(priv->port_base + ADDRQ_STAT) & TX_CNT_INUSE_MASK; 189 + txq->skb[txq->tail] = NULL; 190 + txq->tail = (txq->tail + 1) % txq->num; 191 + } 192 + 193 + netdev_completed_queue(dev, pkts_compl, bytes_compl); 194 + 195 + if (unlikely(netif_queue_stopped(dev)) && pkts_compl) 196 + netif_wake_queue(dev); 197 + 198 + netif_tx_unlock(dev); 199 + } 200 + 201 + static void hisi_femac_adjust_link(struct net_device *dev) 202 + { 203 + struct hisi_femac_priv *priv = netdev_priv(dev); 204 + struct phy_device *phy = dev->phydev; 205 + u32 status = 0; 206 + 207 + if (phy->link) 208 + status |= MAC_PORTSET_LINKED; 209 + if (phy->duplex == DUPLEX_FULL) 210 + status |= MAC_PORTSET_DUPLEX_FULL; 211 + if (phy->speed == SPEED_100) 212 + status |= MAC_PORTSET_SPEED_100M; 213 + 214 + if ((status != priv->link_status) && 215 + ((status | priv->link_status) & MAC_PORTSET_LINKED)) { 216 + writel(status, priv->port_base + MAC_PORTSET); 217 + priv->link_status = status; 218 + phy_print_status(phy); 219 + } 220 + } 221 + 222 + static void hisi_femac_rx_refill(struct hisi_femac_priv *priv) 223 + { 224 + struct hisi_femac_queue *rxq = &priv->rxq; 225 + struct sk_buff *skb; 226 + u32 pos; 227 + u32 len = MAX_FRAME_SIZE; 228 + dma_addr_t addr; 229 + 230 + pos = rxq->head; 231 + while (readl(priv->port_base + ADDRQ_STAT) & BIT_RX_READY) { 232 + if (!CIRC_SPACE(pos, rxq->tail, rxq->num)) 233 + break; 234 + if (unlikely(rxq->skb[pos])) { 235 + netdev_err(priv->ndev, "err skb[%d]=%p\n", 236 + pos, rxq->skb[pos]); 237 + break; 238 + } 239 + skb = netdev_alloc_skb_ip_align(priv->ndev, len); 240 + if (unlikely(!skb)) 241 + break; 242 + 243 + addr = dma_map_single(priv->dev, skb->data, len, 244 + DMA_FROM_DEVICE); 245 + if (dma_mapping_error(priv->dev, addr)) { 246 + dev_kfree_skb_any(skb); 247 + break; 248 + } 249 + rxq->dma_phys[pos] = addr; 250 + rxq->skb[pos] = skb; 251 + writel(addr, priv->port_base + IQ_ADDR); 252 + pos = (pos + 1) % rxq->num; 253 + } 254 + rxq->head = pos; 255 + } 256 + 257 + static int hisi_femac_rx(struct net_device *dev, int limit) 258 + { 259 + struct hisi_femac_priv *priv = netdev_priv(dev); 260 + struct hisi_femac_queue *rxq = &priv->rxq; 261 + struct sk_buff *skb; 262 + dma_addr_t addr; 263 + u32 rx_pkt_info, pos, len, rx_pkts_num = 0; 264 + 265 + pos = rxq->tail; 266 + while (readl(priv->glb_base + GLB_IRQ_RAW) & IRQ_INT_RX_RDY) { 267 + rx_pkt_info = readl(priv->port_base + IQFRM_DES); 268 + len = rx_pkt_info & RX_FRAME_LEN_MASK; 269 + len -= ETH_FCS_LEN; 270 + 271 + /* tell hardware we will deal with this packet */ 272 + writel(IRQ_INT_RX_RDY, priv->glb_base + GLB_IRQ_RAW); 273 + 274 + rx_pkts_num++; 275 + 276 + skb = rxq->skb[pos]; 277 + if (unlikely(!skb)) { 278 + netdev_err(dev, "rx skb NULL. pos=%d\n", pos); 279 + break; 280 + } 281 + rxq->skb[pos] = NULL; 282 + 283 + addr = rxq->dma_phys[pos]; 284 + dma_unmap_single(priv->dev, addr, MAX_FRAME_SIZE, 285 + DMA_FROM_DEVICE); 286 + skb_put(skb, len); 287 + if (unlikely(skb->len > MAX_FRAME_SIZE)) { 288 + netdev_err(dev, "rcv len err, len = %d\n", skb->len); 289 + dev->stats.rx_errors++; 290 + dev->stats.rx_length_errors++; 291 + dev_kfree_skb_any(skb); 292 + goto next; 293 + } 294 + 295 + skb->protocol = eth_type_trans(skb, dev); 296 + napi_gro_receive(&priv->napi, skb); 297 + dev->stats.rx_packets++; 298 + dev->stats.rx_bytes += skb->len; 299 + next: 300 + pos = (pos + 1) % rxq->num; 301 + if (rx_pkts_num >= limit) 302 + break; 303 + } 304 + rxq->tail = pos; 305 + 306 + hisi_femac_rx_refill(priv); 307 + 308 + return rx_pkts_num; 309 + } 310 + 311 + static int hisi_femac_poll(struct napi_struct *napi, int budget) 312 + { 313 + struct hisi_femac_priv *priv = container_of(napi, 314 + struct hisi_femac_priv, napi); 315 + struct net_device *dev = priv->ndev; 316 + int work_done = 0, task = budget; 317 + int ints, num; 318 + 319 + do { 320 + hisi_femac_xmit_reclaim(dev); 321 + num = hisi_femac_rx(dev, task); 322 + work_done += num; 323 + task -= num; 324 + if (work_done >= budget) 325 + break; 326 + 327 + ints = readl(priv->glb_base + GLB_IRQ_RAW); 328 + writel(ints & DEF_INT_MASK, 329 + priv->glb_base + GLB_IRQ_RAW); 330 + } while (ints & DEF_INT_MASK); 331 + 332 + if (work_done < budget) { 333 + napi_complete(napi); 334 + hisi_femac_irq_enable(priv, DEF_INT_MASK & 335 + (~IRQ_INT_TX_PER_PACKET)); 336 + } 337 + 338 + return work_done; 339 + } 340 + 341 + static irqreturn_t hisi_femac_interrupt(int irq, void *dev_id) 342 + { 343 + int ints; 344 + struct net_device *dev = (struct net_device *)dev_id; 345 + struct hisi_femac_priv *priv = netdev_priv(dev); 346 + 347 + ints = readl(priv->glb_base + GLB_IRQ_RAW); 348 + 349 + if (likely(ints & DEF_INT_MASK)) { 350 + writel(ints & DEF_INT_MASK, 351 + priv->glb_base + GLB_IRQ_RAW); 352 + hisi_femac_irq_disable(priv, DEF_INT_MASK); 353 + napi_schedule(&priv->napi); 354 + } 355 + 356 + return IRQ_HANDLED; 357 + } 358 + 359 + static int hisi_femac_init_queue(struct device *dev, 360 + struct hisi_femac_queue *queue, 361 + unsigned int num) 362 + { 363 + queue->skb = devm_kcalloc(dev, num, sizeof(struct sk_buff *), 364 + GFP_KERNEL); 365 + if (!queue->skb) 366 + return -ENOMEM; 367 + 368 + queue->dma_phys = devm_kcalloc(dev, num, sizeof(dma_addr_t), 369 + GFP_KERNEL); 370 + if (!queue->dma_phys) 371 + return -ENOMEM; 372 + 373 + queue->num = num; 374 + queue->head = 0; 375 + queue->tail = 0; 376 + 377 + return 0; 378 + } 379 + 380 + static int hisi_femac_init_tx_and_rx_queues(struct hisi_femac_priv *priv) 381 + { 382 + int ret; 383 + 384 + ret = hisi_femac_init_queue(priv->dev, &priv->txq, TXQ_NUM); 385 + if (ret) 386 + return ret; 387 + 388 + ret = hisi_femac_init_queue(priv->dev, &priv->rxq, RXQ_NUM); 389 + if (ret) 390 + return ret; 391 + 392 + priv->tx_fifo_used_cnt = 0; 393 + 394 + return 0; 395 + } 396 + 397 + static void hisi_femac_free_skb_rings(struct hisi_femac_priv *priv) 398 + { 399 + struct hisi_femac_queue *txq = &priv->txq; 400 + struct hisi_femac_queue *rxq = &priv->rxq; 401 + struct sk_buff *skb; 402 + dma_addr_t dma_addr; 403 + u32 pos; 404 + 405 + pos = rxq->tail; 406 + while (pos != rxq->head) { 407 + skb = rxq->skb[pos]; 408 + if (unlikely(!skb)) { 409 + netdev_err(priv->ndev, "NULL rx skb. pos=%d, head=%d\n", 410 + pos, rxq->head); 411 + continue; 412 + } 413 + 414 + dma_addr = rxq->dma_phys[pos]; 415 + dma_unmap_single(priv->dev, dma_addr, MAX_FRAME_SIZE, 416 + DMA_FROM_DEVICE); 417 + 418 + dev_kfree_skb_any(skb); 419 + rxq->skb[pos] = NULL; 420 + pos = (pos + 1) % rxq->num; 421 + } 422 + rxq->tail = pos; 423 + 424 + pos = txq->tail; 425 + while (pos != txq->head) { 426 + skb = txq->skb[pos]; 427 + if (unlikely(!skb)) { 428 + netdev_err(priv->ndev, "NULL tx skb. pos=%d, head=%d\n", 429 + pos, txq->head); 430 + continue; 431 + } 432 + hisi_femac_tx_dma_unmap(priv, skb, pos); 433 + dev_kfree_skb_any(skb); 434 + txq->skb[pos] = NULL; 435 + pos = (pos + 1) % txq->num; 436 + } 437 + txq->tail = pos; 438 + priv->tx_fifo_used_cnt = 0; 439 + } 440 + 441 + static int hisi_femac_set_hw_mac_addr(struct hisi_femac_priv *priv, 442 + unsigned char *mac) 443 + { 444 + u32 reg; 445 + 446 + reg = mac[1] | (mac[0] << 8); 447 + writel(reg, priv->glb_base + GLB_HOSTMAC_H16); 448 + 449 + reg = mac[5] | (mac[4] << 8) | (mac[3] << 16) | (mac[2] << 24); 450 + writel(reg, priv->glb_base + GLB_HOSTMAC_L32); 451 + 452 + return 0; 453 + } 454 + 455 + static int hisi_femac_port_reset(struct hisi_femac_priv *priv) 456 + { 457 + u32 val; 458 + 459 + val = readl(priv->glb_base + GLB_SOFT_RESET); 460 + val |= SOFT_RESET_ALL; 461 + writel(val, priv->glb_base + GLB_SOFT_RESET); 462 + 463 + usleep_range(500, 800); 464 + 465 + val &= ~SOFT_RESET_ALL; 466 + writel(val, priv->glb_base + GLB_SOFT_RESET); 467 + 468 + return 0; 469 + } 470 + 471 + static int hisi_femac_net_open(struct net_device *dev) 472 + { 473 + struct hisi_femac_priv *priv = netdev_priv(dev); 474 + 475 + hisi_femac_port_reset(priv); 476 + hisi_femac_set_hw_mac_addr(priv, dev->dev_addr); 477 + hisi_femac_rx_refill(priv); 478 + 479 + netif_carrier_off(dev); 480 + netdev_reset_queue(dev); 481 + netif_start_queue(dev); 482 + napi_enable(&priv->napi); 483 + 484 + priv->link_status = 0; 485 + if (dev->phydev) 486 + phy_start(dev->phydev); 487 + 488 + writel(IRQ_ENA_PORT0_MASK, priv->glb_base + GLB_IRQ_RAW); 489 + hisi_femac_irq_enable(priv, IRQ_ENA_ALL | IRQ_ENA_PORT0 | DEF_INT_MASK); 490 + 491 + return 0; 492 + } 493 + 494 + static int hisi_femac_net_close(struct net_device *dev) 495 + { 496 + struct hisi_femac_priv *priv = netdev_priv(dev); 497 + 498 + hisi_femac_irq_disable(priv, IRQ_ENA_PORT0); 499 + 500 + if (dev->phydev) 501 + phy_stop(dev->phydev); 502 + 503 + netif_stop_queue(dev); 504 + napi_disable(&priv->napi); 505 + 506 + hisi_femac_free_skb_rings(priv); 507 + 508 + return 0; 509 + } 510 + 511 + static netdev_tx_t hisi_femac_net_xmit(struct sk_buff *skb, 512 + struct net_device *dev) 513 + { 514 + struct hisi_femac_priv *priv = netdev_priv(dev); 515 + struct hisi_femac_queue *txq = &priv->txq; 516 + dma_addr_t addr; 517 + u32 val; 518 + 519 + val = readl(priv->port_base + ADDRQ_STAT); 520 + val &= BIT_TX_READY; 521 + if (!val) { 522 + hisi_femac_irq_enable(priv, IRQ_INT_TX_PER_PACKET); 523 + dev->stats.tx_dropped++; 524 + dev->stats.tx_fifo_errors++; 525 + netif_stop_queue(dev); 526 + return NETDEV_TX_BUSY; 527 + } 528 + 529 + if (unlikely(!CIRC_SPACE(txq->head, txq->tail, 530 + txq->num))) { 531 + hisi_femac_irq_enable(priv, IRQ_INT_TX_PER_PACKET); 532 + dev->stats.tx_dropped++; 533 + dev->stats.tx_fifo_errors++; 534 + netif_stop_queue(dev); 535 + return NETDEV_TX_BUSY; 536 + } 537 + 538 + addr = dma_map_single(priv->dev, skb->data, 539 + skb->len, DMA_TO_DEVICE); 540 + if (unlikely(dma_mapping_error(priv->dev, addr))) { 541 + dev_kfree_skb_any(skb); 542 + dev->stats.tx_dropped++; 543 + return NETDEV_TX_OK; 544 + } 545 + txq->dma_phys[txq->head] = addr; 546 + 547 + txq->skb[txq->head] = skb; 548 + txq->head = (txq->head + 1) % txq->num; 549 + 550 + writel(addr, priv->port_base + EQ_ADDR); 551 + writel(skb->len + ETH_FCS_LEN, priv->port_base + EQFRM_LEN); 552 + 553 + priv->tx_fifo_used_cnt++; 554 + 555 + dev->stats.tx_packets++; 556 + dev->stats.tx_bytes += skb->len; 557 + netdev_sent_queue(dev, skb->len); 558 + 559 + return NETDEV_TX_OK; 560 + } 561 + 562 + static int hisi_femac_set_mac_address(struct net_device *dev, void *p) 563 + { 564 + struct hisi_femac_priv *priv = netdev_priv(dev); 565 + struct sockaddr *skaddr = p; 566 + 567 + if (!is_valid_ether_addr(skaddr->sa_data)) 568 + return -EADDRNOTAVAIL; 569 + 570 + memcpy(dev->dev_addr, skaddr->sa_data, dev->addr_len); 571 + dev->addr_assign_type &= ~NET_ADDR_RANDOM; 572 + 573 + hisi_femac_set_hw_mac_addr(priv, dev->dev_addr); 574 + 575 + return 0; 576 + } 577 + 578 + static void hisi_femac_enable_hw_addr_filter(struct hisi_femac_priv *priv, 579 + unsigned int reg_n, bool enable) 580 + { 581 + u32 val; 582 + 583 + val = readl(priv->glb_base + GLB_MAC_H16(reg_n)); 584 + if (enable) 585 + val |= BIT_MACFLT_ENA; 586 + else 587 + val &= ~BIT_MACFLT_ENA; 588 + writel(val, priv->glb_base + GLB_MAC_H16(reg_n)); 589 + } 590 + 591 + static void hisi_femac_set_hw_addr_filter(struct hisi_femac_priv *priv, 592 + unsigned char *addr, 593 + unsigned int reg_n) 594 + { 595 + unsigned int high, low; 596 + u32 val; 597 + 598 + high = GLB_MAC_H16(reg_n); 599 + low = GLB_MAC_L32(reg_n); 600 + 601 + val = (addr[2] << 24) | (addr[3] << 16) | (addr[4] << 8) | addr[5]; 602 + writel(val, priv->glb_base + low); 603 + 604 + val = readl(priv->glb_base + high); 605 + val &= ~MACFLT_HI16_MASK; 606 + val |= ((addr[0] << 8) | addr[1]); 607 + val |= (BIT_MACFLT_ENA | BIT_MACFLT_FW2CPU); 608 + writel(val, priv->glb_base + high); 609 + } 610 + 611 + static void hisi_femac_set_promisc_mode(struct hisi_femac_priv *priv, 612 + bool promisc_mode) 613 + { 614 + u32 val; 615 + 616 + val = readl(priv->glb_base + GLB_FWCTRL); 617 + if (promisc_mode) 618 + val |= FWCTRL_FWALL2CPU; 619 + else 620 + val &= ~FWCTRL_FWALL2CPU; 621 + writel(val, priv->glb_base + GLB_FWCTRL); 622 + } 623 + 624 + /* Handle multiple multicast addresses (perfect filtering)*/ 625 + static void hisi_femac_set_mc_addr_filter(struct hisi_femac_priv *priv) 626 + { 627 + struct net_device *dev = priv->ndev; 628 + u32 val; 629 + 630 + val = readl(priv->glb_base + GLB_MACTCTRL); 631 + if ((netdev_mc_count(dev) > MAX_MULTICAST_ADDRESSES) || 632 + (dev->flags & IFF_ALLMULTI)) { 633 + val |= MACTCTRL_MULTI2CPU; 634 + } else { 635 + int reg = MAX_UNICAST_ADDRESSES; 636 + int i; 637 + struct netdev_hw_addr *ha; 638 + 639 + for (i = reg; i < MAX_MAC_FILTER_NUM; i++) 640 + hisi_femac_enable_hw_addr_filter(priv, i, false); 641 + 642 + netdev_for_each_mc_addr(ha, dev) { 643 + hisi_femac_set_hw_addr_filter(priv, ha->addr, reg); 644 + reg++; 645 + } 646 + val &= ~MACTCTRL_MULTI2CPU; 647 + } 648 + writel(val, priv->glb_base + GLB_MACTCTRL); 649 + } 650 + 651 + /* Handle multiple unicast addresses (perfect filtering)*/ 652 + static void hisi_femac_set_uc_addr_filter(struct hisi_femac_priv *priv) 653 + { 654 + struct net_device *dev = priv->ndev; 655 + u32 val; 656 + 657 + val = readl(priv->glb_base + GLB_MACTCTRL); 658 + if (netdev_uc_count(dev) > MAX_UNICAST_ADDRESSES) { 659 + val |= MACTCTRL_UNI2CPU; 660 + } else { 661 + int reg = 0; 662 + int i; 663 + struct netdev_hw_addr *ha; 664 + 665 + for (i = reg; i < MAX_UNICAST_ADDRESSES; i++) 666 + hisi_femac_enable_hw_addr_filter(priv, i, false); 667 + 668 + netdev_for_each_uc_addr(ha, dev) { 669 + hisi_femac_set_hw_addr_filter(priv, ha->addr, reg); 670 + reg++; 671 + } 672 + val &= ~MACTCTRL_UNI2CPU; 673 + } 674 + writel(val, priv->glb_base + GLB_MACTCTRL); 675 + } 676 + 677 + static void hisi_femac_net_set_rx_mode(struct net_device *dev) 678 + { 679 + struct hisi_femac_priv *priv = netdev_priv(dev); 680 + 681 + if (dev->flags & IFF_PROMISC) { 682 + hisi_femac_set_promisc_mode(priv, true); 683 + } else { 684 + hisi_femac_set_promisc_mode(priv, false); 685 + hisi_femac_set_mc_addr_filter(priv); 686 + hisi_femac_set_uc_addr_filter(priv); 687 + } 688 + } 689 + 690 + static int hisi_femac_net_ioctl(struct net_device *dev, 691 + struct ifreq *ifreq, int cmd) 692 + { 693 + if (!netif_running(dev)) 694 + return -EINVAL; 695 + 696 + if (!dev->phydev) 697 + return -EINVAL; 698 + 699 + return phy_mii_ioctl(dev->phydev, ifreq, cmd); 700 + } 701 + 702 + static struct ethtool_ops hisi_femac_ethtools_ops = { 703 + .get_link = ethtool_op_get_link, 704 + .get_link_ksettings = phy_ethtool_get_link_ksettings, 705 + .set_link_ksettings = phy_ethtool_set_link_ksettings, 706 + }; 707 + 708 + static const struct net_device_ops hisi_femac_netdev_ops = { 709 + .ndo_open = hisi_femac_net_open, 710 + .ndo_stop = hisi_femac_net_close, 711 + .ndo_start_xmit = hisi_femac_net_xmit, 712 + .ndo_do_ioctl = hisi_femac_net_ioctl, 713 + .ndo_set_mac_address = hisi_femac_set_mac_address, 714 + .ndo_set_rx_mode = hisi_femac_net_set_rx_mode, 715 + .ndo_change_mtu = eth_change_mtu, 716 + }; 717 + 718 + static void hisi_femac_core_reset(struct hisi_femac_priv *priv) 719 + { 720 + reset_control_assert(priv->mac_rst); 721 + reset_control_deassert(priv->mac_rst); 722 + } 723 + 724 + static void hisi_femac_sleep_us(u32 time_us) 725 + { 726 + u32 time_ms; 727 + 728 + if (!time_us) 729 + return; 730 + 731 + time_ms = DIV_ROUND_UP(time_us, 1000); 732 + if (time_ms < 20) 733 + usleep_range(time_us, time_us + 500); 734 + else 735 + msleep(time_ms); 736 + } 737 + 738 + static void hisi_femac_phy_reset(struct hisi_femac_priv *priv) 739 + { 740 + /* To make sure PHY hardware reset success, 741 + * we must keep PHY in deassert state first and 742 + * then complete the hardware reset operation 743 + */ 744 + reset_control_deassert(priv->phy_rst); 745 + hisi_femac_sleep_us(priv->phy_reset_delays[PRE_DELAY]); 746 + 747 + reset_control_assert(priv->phy_rst); 748 + /* delay some time to ensure reset ok, 749 + * this depends on PHY hardware feature 750 + */ 751 + hisi_femac_sleep_us(priv->phy_reset_delays[PULSE]); 752 + reset_control_deassert(priv->phy_rst); 753 + /* delay some time to ensure later MDIO access */ 754 + hisi_femac_sleep_us(priv->phy_reset_delays[POST_DELAY]); 755 + } 756 + 757 + static void hisi_femac_port_init(struct hisi_femac_priv *priv) 758 + { 759 + u32 val; 760 + 761 + /* MAC gets link status info and phy mode by software config */ 762 + val = MAC_PORTSEL_STAT_CPU; 763 + if (priv->ndev->phydev->interface == PHY_INTERFACE_MODE_RMII) 764 + val |= MAC_PORTSEL_RMII; 765 + writel(val, priv->port_base + MAC_PORTSEL); 766 + 767 + /*clear all interrupt status */ 768 + writel(IRQ_ENA_PORT0_MASK, priv->glb_base + GLB_IRQ_RAW); 769 + hisi_femac_irq_disable(priv, IRQ_ENA_PORT0_MASK | IRQ_ENA_PORT0); 770 + 771 + val = readl(priv->glb_base + GLB_FWCTRL); 772 + val &= ~(FWCTRL_VLAN_ENABLE | FWCTRL_FWALL2CPU); 773 + val |= FWCTRL_FW2CPU_ENA; 774 + writel(val, priv->glb_base + GLB_FWCTRL); 775 + 776 + val = readl(priv->glb_base + GLB_MACTCTRL); 777 + val |= (MACTCTRL_BROAD2CPU | MACTCTRL_MACT_ENA); 778 + writel(val, priv->glb_base + GLB_MACTCTRL); 779 + 780 + val = readl(priv->port_base + MAC_SET); 781 + val &= ~MAX_FRAME_SIZE_MASK; 782 + val |= MAX_FRAME_SIZE; 783 + writel(val, priv->port_base + MAC_SET); 784 + 785 + val = RX_COALESCED_TIMER | 786 + (RX_COALESCED_FRAMES << RX_COALESCED_FRAME_OFFSET); 787 + writel(val, priv->port_base + RX_COALESCE_SET); 788 + 789 + val = (HW_RX_FIFO_DEPTH << RX_DEPTH_OFFSET) | HW_TX_FIFO_DEPTH; 790 + writel(val, priv->port_base + QLEN_SET); 791 + } 792 + 793 + static int hisi_femac_drv_probe(struct platform_device *pdev) 794 + { 795 + struct device *dev = &pdev->dev; 796 + struct device_node *node = dev->of_node; 797 + struct resource *res; 798 + struct net_device *ndev; 799 + struct hisi_femac_priv *priv; 800 + struct phy_device *phy; 801 + const char *mac_addr; 802 + int ret; 803 + 804 + ndev = alloc_etherdev(sizeof(*priv)); 805 + if (!ndev) 806 + return -ENOMEM; 807 + 808 + platform_set_drvdata(pdev, ndev); 809 + 810 + priv = netdev_priv(ndev); 811 + priv->dev = dev; 812 + priv->ndev = ndev; 813 + 814 + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 815 + priv->port_base = devm_ioremap_resource(dev, res); 816 + if (IS_ERR(priv->port_base)) { 817 + ret = PTR_ERR(priv->port_base); 818 + goto out_free_netdev; 819 + } 820 + 821 + res = platform_get_resource(pdev, IORESOURCE_MEM, 1); 822 + priv->glb_base = devm_ioremap_resource(dev, res); 823 + if (IS_ERR(priv->glb_base)) { 824 + ret = PTR_ERR(priv->glb_base); 825 + goto out_free_netdev; 826 + } 827 + 828 + priv->clk = devm_clk_get(&pdev->dev, NULL); 829 + if (IS_ERR(priv->clk)) { 830 + dev_err(dev, "failed to get clk\n"); 831 + ret = -ENODEV; 832 + goto out_free_netdev; 833 + } 834 + 835 + ret = clk_prepare_enable(priv->clk); 836 + if (ret) { 837 + dev_err(dev, "failed to enable clk %d\n", ret); 838 + goto out_free_netdev; 839 + } 840 + 841 + priv->mac_rst = devm_reset_control_get(dev, "mac"); 842 + if (IS_ERR(priv->mac_rst)) { 843 + ret = PTR_ERR(priv->mac_rst); 844 + goto out_disable_clk; 845 + } 846 + hisi_femac_core_reset(priv); 847 + 848 + priv->phy_rst = devm_reset_control_get(dev, "phy"); 849 + if (IS_ERR(priv->phy_rst)) { 850 + priv->phy_rst = NULL; 851 + } else { 852 + ret = of_property_read_u32_array(node, 853 + PHY_RESET_DELAYS_PROPERTY, 854 + priv->phy_reset_delays, 855 + DELAYS_NUM); 856 + if (ret) 857 + goto out_disable_clk; 858 + hisi_femac_phy_reset(priv); 859 + } 860 + 861 + phy = of_phy_get_and_connect(ndev, node, hisi_femac_adjust_link); 862 + if (!phy) { 863 + dev_err(dev, "connect to PHY failed!\n"); 864 + ret = -ENODEV; 865 + goto out_disable_clk; 866 + } 867 + 868 + phy_attached_print(phy, "phy_id=0x%.8lx, phy_mode=%s\n", 869 + (unsigned long)phy->phy_id, 870 + phy_modes(phy->interface)); 871 + 872 + mac_addr = of_get_mac_address(node); 873 + if (mac_addr) 874 + ether_addr_copy(ndev->dev_addr, mac_addr); 875 + if (!is_valid_ether_addr(ndev->dev_addr)) { 876 + eth_hw_addr_random(ndev); 877 + dev_warn(dev, "using random MAC address %pM\n", 878 + ndev->dev_addr); 879 + } 880 + 881 + ndev->watchdog_timeo = 6 * HZ; 882 + ndev->priv_flags |= IFF_UNICAST_FLT; 883 + ndev->netdev_ops = &hisi_femac_netdev_ops; 884 + ndev->ethtool_ops = &hisi_femac_ethtools_ops; 885 + netif_napi_add(ndev, &priv->napi, hisi_femac_poll, FEMAC_POLL_WEIGHT); 886 + SET_NETDEV_DEV(ndev, &pdev->dev); 887 + 888 + hisi_femac_port_init(priv); 889 + 890 + ret = hisi_femac_init_tx_and_rx_queues(priv); 891 + if (ret) 892 + goto out_disconnect_phy; 893 + 894 + ndev->irq = platform_get_irq(pdev, 0); 895 + if (ndev->irq <= 0) { 896 + dev_err(dev, "No irq resource\n"); 897 + ret = -ENODEV; 898 + goto out_disconnect_phy; 899 + } 900 + 901 + ret = devm_request_irq(dev, ndev->irq, hisi_femac_interrupt, 902 + IRQF_SHARED, pdev->name, ndev); 903 + if (ret) { 904 + dev_err(dev, "devm_request_irq %d failed!\n", ndev->irq); 905 + goto out_disconnect_phy; 906 + } 907 + 908 + ret = register_netdev(ndev); 909 + if (ret) { 910 + dev_err(dev, "register_netdev failed!\n"); 911 + goto out_disconnect_phy; 912 + } 913 + 914 + return ret; 915 + 916 + out_disconnect_phy: 917 + netif_napi_del(&priv->napi); 918 + phy_disconnect(phy); 919 + out_disable_clk: 920 + clk_disable_unprepare(priv->clk); 921 + out_free_netdev: 922 + free_netdev(ndev); 923 + 924 + return ret; 925 + } 926 + 927 + static int hisi_femac_drv_remove(struct platform_device *pdev) 928 + { 929 + struct net_device *ndev = platform_get_drvdata(pdev); 930 + struct hisi_femac_priv *priv = netdev_priv(ndev); 931 + 932 + netif_napi_del(&priv->napi); 933 + unregister_netdev(ndev); 934 + 935 + phy_disconnect(ndev->phydev); 936 + clk_disable_unprepare(priv->clk); 937 + free_netdev(ndev); 938 + 939 + return 0; 940 + } 941 + 942 + #ifdef CONFIG_PM 943 + int hisi_femac_drv_suspend(struct platform_device *pdev, 944 + pm_message_t state) 945 + { 946 + struct net_device *ndev = platform_get_drvdata(pdev); 947 + struct hisi_femac_priv *priv = netdev_priv(ndev); 948 + 949 + disable_irq(ndev->irq); 950 + if (netif_running(ndev)) { 951 + hisi_femac_net_close(ndev); 952 + netif_device_detach(ndev); 953 + } 954 + 955 + clk_disable_unprepare(priv->clk); 956 + 957 + return 0; 958 + } 959 + 960 + int hisi_femac_drv_resume(struct platform_device *pdev) 961 + { 962 + struct net_device *ndev = platform_get_drvdata(pdev); 963 + struct hisi_femac_priv *priv = netdev_priv(ndev); 964 + 965 + clk_prepare_enable(priv->clk); 966 + if (priv->phy_rst) 967 + hisi_femac_phy_reset(priv); 968 + 969 + if (netif_running(ndev)) { 970 + hisi_femac_port_init(priv); 971 + hisi_femac_net_open(ndev); 972 + netif_device_attach(ndev); 973 + } 974 + enable_irq(ndev->irq); 975 + 976 + return 0; 977 + } 978 + #endif 979 + 980 + static const struct of_device_id hisi_femac_match[] = { 981 + {.compatible = "hisilicon,hisi-femac-v1",}, 982 + {.compatible = "hisilicon,hisi-femac-v2",}, 983 + {.compatible = "hisilicon,hi3516cv300-femac",}, 984 + {}, 985 + }; 986 + 987 + MODULE_DEVICE_TABLE(of, hisi_femac_match); 988 + 989 + static struct platform_driver hisi_femac_driver = { 990 + .driver = { 991 + .name = "hisi-femac", 992 + .of_match_table = hisi_femac_match, 993 + }, 994 + .probe = hisi_femac_drv_probe, 995 + .remove = hisi_femac_drv_remove, 996 + #ifdef CONFIG_PM 997 + .suspend = hisi_femac_drv_suspend, 998 + .resume = hisi_femac_drv_resume, 999 + #endif 1000 + }; 1001 + 1002 + module_platform_driver(hisi_femac_driver); 1003 + 1004 + MODULE_DESCRIPTION("Hisilicon Fast Ethernet MAC driver"); 1005 + MODULE_AUTHOR("Dongpo Li <lidongpo@hisilicon.com>"); 1006 + MODULE_LICENSE("GPL v2"); 1007 + MODULE_ALIAS("platform:hisi-femac");
+7
drivers/net/phy/Kconfig
··· 294 294 PEF 7061, PEF 7071 and PEF 7072 or integrated into the Intel 295 295 SoCs xRX200, xRX300, xRX330, xRX350 and xRX550. 296 296 297 + config MDIO_HISI_FEMAC 298 + tristate "Hisilicon FEMAC MDIO bus controller" 299 + depends on HAS_IOMEM && OF_MDIO 300 + help 301 + This module provides a driver for the MDIO busses found in the 302 + Hisilicon SoC that have an Fast Ethernet MAC. 303 + 297 304 endif # PHYLIB 298 305 299 306 config MICREL_KS8995MA
+1
drivers/net/phy/Makefile
··· 47 47 obj-$(CONFIG_MICROCHIP_PHY) += microchip.o 48 48 obj-$(CONFIG_MDIO_BCM_IPROC) += mdio-bcm-iproc.o 49 49 obj-$(CONFIG_INTEL_XWAY_PHY) += intel-xway.o 50 + obj-$(CONFIG_MDIO_HISI_FEMAC) += mdio-hisi-femac.o
+166
drivers/net/phy/mdio-hisi-femac.c
··· 1 + /* 2 + * Hisilicon Fast Ethernet MDIO Bus Driver 3 + * 4 + * Copyright (c) 2016 HiSilicon Technologies Co., Ltd. 5 + * 6 + * This program is free software; you can redistribute it and/or modify 7 + * it under the terms of the GNU General Public License as published by 8 + * the Free Software Foundation; either version 2 of the License, or 9 + * (at your option) any later version. 10 + * 11 + * This program is distributed in the hope that it will be useful, 12 + * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 + * GNU General Public License for more details. 15 + * 16 + * You should have received a copy of the GNU General Public License 17 + * along with this program. If not, see <http://www.gnu.org/licenses/>. 18 + */ 19 + 20 + #include <linux/clk.h> 21 + #include <linux/iopoll.h> 22 + #include <linux/kernel.h> 23 + #include <linux/module.h> 24 + #include <linux/of_address.h> 25 + #include <linux/of_mdio.h> 26 + #include <linux/platform_device.h> 27 + 28 + #define MDIO_RWCTRL 0x00 29 + #define MDIO_RO_DATA 0x04 30 + #define MDIO_WRITE BIT(13) 31 + #define MDIO_RW_FINISH BIT(15) 32 + #define BIT_PHY_ADDR_OFFSET 8 33 + #define BIT_WR_DATA_OFFSET 16 34 + 35 + struct hisi_femac_mdio_data { 36 + struct clk *clk; 37 + void __iomem *membase; 38 + }; 39 + 40 + static int hisi_femac_mdio_wait_ready(struct hisi_femac_mdio_data *data) 41 + { 42 + u32 val; 43 + 44 + return readl_poll_timeout(data->membase + MDIO_RWCTRL, 45 + val, val & MDIO_RW_FINISH, 20, 10000); 46 + } 47 + 48 + static int hisi_femac_mdio_read(struct mii_bus *bus, int mii_id, int regnum) 49 + { 50 + struct hisi_femac_mdio_data *data = bus->priv; 51 + int ret; 52 + 53 + ret = hisi_femac_mdio_wait_ready(data); 54 + if (ret) 55 + return ret; 56 + 57 + writel((mii_id << BIT_PHY_ADDR_OFFSET) | regnum, 58 + data->membase + MDIO_RWCTRL); 59 + 60 + ret = hisi_femac_mdio_wait_ready(data); 61 + if (ret) 62 + return ret; 63 + 64 + return readl(data->membase + MDIO_RO_DATA) & 0xFFFF; 65 + } 66 + 67 + static int hisi_femac_mdio_write(struct mii_bus *bus, int mii_id, int regnum, 68 + u16 value) 69 + { 70 + struct hisi_femac_mdio_data *data = bus->priv; 71 + int ret; 72 + 73 + ret = hisi_femac_mdio_wait_ready(data); 74 + if (ret) 75 + return ret; 76 + 77 + writel(MDIO_WRITE | (value << BIT_WR_DATA_OFFSET) | 78 + (mii_id << BIT_PHY_ADDR_OFFSET) | regnum, 79 + data->membase + MDIO_RWCTRL); 80 + 81 + return hisi_femac_mdio_wait_ready(data); 82 + } 83 + 84 + static int hisi_femac_mdio_probe(struct platform_device *pdev) 85 + { 86 + struct device_node *np = pdev->dev.of_node; 87 + struct mii_bus *bus; 88 + struct hisi_femac_mdio_data *data; 89 + struct resource *res; 90 + int ret; 91 + 92 + bus = mdiobus_alloc_size(sizeof(*data)); 93 + if (!bus) 94 + return -ENOMEM; 95 + 96 + bus->name = "hisi_femac_mii_bus"; 97 + bus->read = &hisi_femac_mdio_read; 98 + bus->write = &hisi_femac_mdio_write; 99 + snprintf(bus->id, MII_BUS_ID_SIZE, "%s", pdev->name); 100 + bus->parent = &pdev->dev; 101 + 102 + data = bus->priv; 103 + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 104 + data->membase = devm_ioremap_resource(&pdev->dev, res); 105 + if (IS_ERR(data->membase)) { 106 + ret = PTR_ERR(data->membase); 107 + goto err_out_free_mdiobus; 108 + } 109 + 110 + data->clk = devm_clk_get(&pdev->dev, NULL); 111 + if (IS_ERR(data->clk)) { 112 + ret = PTR_ERR(data->clk); 113 + goto err_out_free_mdiobus; 114 + } 115 + 116 + ret = clk_prepare_enable(data->clk); 117 + if (ret) 118 + goto err_out_free_mdiobus; 119 + 120 + ret = of_mdiobus_register(bus, np); 121 + if (ret) 122 + goto err_out_disable_clk; 123 + 124 + platform_set_drvdata(pdev, bus); 125 + 126 + return 0; 127 + 128 + err_out_disable_clk: 129 + clk_disable_unprepare(data->clk); 130 + err_out_free_mdiobus: 131 + mdiobus_free(bus); 132 + return ret; 133 + } 134 + 135 + static int hisi_femac_mdio_remove(struct platform_device *pdev) 136 + { 137 + struct mii_bus *bus = platform_get_drvdata(pdev); 138 + struct hisi_femac_mdio_data *data = bus->priv; 139 + 140 + mdiobus_unregister(bus); 141 + clk_disable_unprepare(data->clk); 142 + mdiobus_free(bus); 143 + 144 + return 0; 145 + } 146 + 147 + static const struct of_device_id hisi_femac_mdio_dt_ids[] = { 148 + { .compatible = "hisilicon,hisi-femac-mdio" }, 149 + { } 150 + }; 151 + MODULE_DEVICE_TABLE(of, hisi_femac_mdio_dt_ids); 152 + 153 + static struct platform_driver hisi_femac_mdio_driver = { 154 + .probe = hisi_femac_mdio_probe, 155 + .remove = hisi_femac_mdio_remove, 156 + .driver = { 157 + .name = "hisi-femac-mdio", 158 + .of_match_table = hisi_femac_mdio_dt_ids, 159 + }, 160 + }; 161 + 162 + module_platform_driver(hisi_femac_mdio_driver); 163 + 164 + MODULE_DESCRIPTION("Hisilicon Fast Ethernet MAC MDIO interface driver"); 165 + MODULE_AUTHOR("Dongpo Li <lidongpo@hisilicon.com>"); 166 + MODULE_LICENSE("GPL v2");
+36
drivers/of/of_mdio.c
··· 19 19 #include <linux/of_gpio.h> 20 20 #include <linux/of_irq.h> 21 21 #include <linux/of_mdio.h> 22 + #include <linux/of_net.h> 22 23 #include <linux/module.h> 23 24 24 25 MODULE_AUTHOR("Grant Likely <grant.likely@secretlab.ca>"); ··· 331 330 return ret ? NULL : phy; 332 331 } 333 332 EXPORT_SYMBOL(of_phy_connect); 333 + 334 + /** 335 + * of_phy_get_and_connect 336 + * - Get phy node and connect to the phy described in the device tree 337 + * @dev: pointer to net_device claiming the phy 338 + * @np: Pointer to device tree node for the net_device claiming the phy 339 + * @hndlr: Link state callback for the network device 340 + * 341 + * If successful, returns a pointer to the phy_device with the embedded 342 + * struct device refcount incremented by one, or NULL on failure. The 343 + * refcount must be dropped by calling phy_disconnect() or phy_detach(). 344 + */ 345 + struct phy_device *of_phy_get_and_connect(struct net_device *dev, 346 + struct device_node *np, 347 + void (*hndlr)(struct net_device *)) 348 + { 349 + phy_interface_t iface; 350 + struct device_node *phy_np; 351 + struct phy_device *phy; 352 + 353 + iface = of_get_phy_mode(np); 354 + if (iface < 0) 355 + return NULL; 356 + 357 + phy_np = of_parse_phandle(np, "phy-handle", 0); 358 + if (!phy_np) 359 + return NULL; 360 + 361 + phy = of_phy_connect(dev, phy_np, hndlr, 0, iface); 362 + 363 + of_node_put(phy_np); 364 + 365 + return phy; 366 + } 367 + EXPORT_SYMBOL(of_phy_get_and_connect); 334 368 335 369 /** 336 370 * of_phy_attach - Attach to a PHY without starting the state machine
+10
include/linux/of_mdio.h
··· 19 19 struct device_node *phy_np, 20 20 void (*hndlr)(struct net_device *), 21 21 u32 flags, phy_interface_t iface); 22 + extern struct phy_device * 23 + of_phy_get_and_connect(struct net_device *dev, struct device_node *np, 24 + void (*hndlr)(struct net_device *)); 22 25 struct phy_device *of_phy_attach(struct net_device *dev, 23 26 struct device_node *phy_np, u32 flags, 24 27 phy_interface_t iface); ··· 51 48 struct device_node *phy_np, 52 49 void (*hndlr)(struct net_device *), 53 50 u32 flags, phy_interface_t iface) 51 + { 52 + return NULL; 53 + } 54 + 55 + static inline struct phy_device * 56 + of_phy_get_and_connect(struct net_device *dev, struct device_node *np, 57 + void (*hndlr)(struct net_device *)) 54 58 { 55 59 return NULL; 56 60 }