1511f6c1aSRoger Quadros // SPDX-License-Identifier: GPL-2.0 2511f6c1aSRoger Quadros 3511f6c1aSRoger Quadros /* Texas Instruments ICSSM Ethernet Driver 4511f6c1aSRoger Quadros * 5511f6c1aSRoger Quadros * Copyright (C) 2018-2022 Texas Instruments Incorporated - https://www.ti.com/ 6511f6c1aSRoger Quadros * 7511f6c1aSRoger Quadros */ 8511f6c1aSRoger Quadros 9511f6c1aSRoger Quadros #include <linux/etherdevice.h> 10511f6c1aSRoger Quadros #include <linux/genalloc.h> 11511f6c1aSRoger Quadros #include <linux/if_bridge.h> 12511f6c1aSRoger Quadros #include <linux/if_hsr.h> 13511f6c1aSRoger Quadros #include <linux/if_vlan.h> 14511f6c1aSRoger Quadros #include <linux/interrupt.h> 15511f6c1aSRoger Quadros #include <linux/kernel.h> 16511f6c1aSRoger Quadros #include <linux/mfd/syscon.h> 17511f6c1aSRoger Quadros #include <linux/module.h> 18511f6c1aSRoger Quadros #include <linux/net_tstamp.h> 19511f6c1aSRoger Quadros #include <linux/of.h> 20511f6c1aSRoger Quadros #include <linux/of_irq.h> 21511f6c1aSRoger Quadros #include <linux/of_mdio.h> 22511f6c1aSRoger Quadros #include <linux/of_net.h> 23511f6c1aSRoger Quadros #include <linux/platform_device.h> 24511f6c1aSRoger Quadros #include <linux/phy.h> 25511f6c1aSRoger Quadros #include <linux/remoteproc/pruss.h> 26511f6c1aSRoger Quadros #include <linux/ptp_classify.h> 27511f6c1aSRoger Quadros #include <linux/regmap.h> 28511f6c1aSRoger Quadros #include <linux/remoteproc.h> 29511f6c1aSRoger Quadros #include <net/pkt_cls.h> 30511f6c1aSRoger Quadros 31511f6c1aSRoger Quadros #include "icssm_prueth.h" 32*a99b5657SRoger Quadros #include "../icssg/icssg_mii_rt.h" 33*a99b5657SRoger Quadros 34*a99b5657SRoger Quadros #define OCMC_RAM_SIZE (SZ_64K) 35*a99b5657SRoger Quadros 36*a99b5657SRoger Quadros #define TX_START_DELAY 0x40 37*a99b5657SRoger Quadros #define TX_CLK_DELAY_100M 0x6 38*a99b5657SRoger Quadros 39*a99b5657SRoger Quadros /* Below macro is for 1528 Byte Frame support, to Allow even with 40*a99b5657SRoger Quadros * Redundancy tag 41*a99b5657SRoger Quadros */ 42*a99b5657SRoger Quadros #define PRUSS_MII_RT_RX_FRMS_MAX_SUPPORT_EMAC (VLAN_ETH_FRAME_LEN + \ 43*a99b5657SRoger Quadros ETH_FCS_LEN + \ 44*a99b5657SRoger Quadros ICSSM_LRE_TAG_SIZE) 45*a99b5657SRoger Quadros 46*a99b5657SRoger Quadros /* ensure that order of PRUSS mem regions is same as enum prueth_mem */ 47*a99b5657SRoger Quadros static enum pruss_mem pruss_mem_ids[] = { PRUSS_MEM_DRAM0, PRUSS_MEM_DRAM1, 48*a99b5657SRoger Quadros PRUSS_MEM_SHRD_RAM2 }; 49*a99b5657SRoger Quadros 50*a99b5657SRoger Quadros static const struct prueth_queue_info queue_infos[][NUM_QUEUES] = { 51*a99b5657SRoger Quadros [PRUETH_PORT_QUEUE_HOST] = { 52*a99b5657SRoger Quadros [PRUETH_QUEUE1] = { 53*a99b5657SRoger Quadros P0_Q1_BUFFER_OFFSET, 54*a99b5657SRoger Quadros HOST_QUEUE_DESC_OFFSET, 55*a99b5657SRoger Quadros P0_Q1_BD_OFFSET, 56*a99b5657SRoger Quadros P0_Q1_BD_OFFSET + ((HOST_QUEUE_1_SIZE - 1) * BD_SIZE), 57*a99b5657SRoger Quadros }, 58*a99b5657SRoger Quadros [PRUETH_QUEUE2] = { 59*a99b5657SRoger Quadros P0_Q2_BUFFER_OFFSET, 60*a99b5657SRoger Quadros HOST_QUEUE_DESC_OFFSET + 8, 61*a99b5657SRoger Quadros P0_Q2_BD_OFFSET, 62*a99b5657SRoger Quadros P0_Q2_BD_OFFSET + ((HOST_QUEUE_2_SIZE - 1) * BD_SIZE), 63*a99b5657SRoger Quadros }, 64*a99b5657SRoger Quadros [PRUETH_QUEUE3] = { 65*a99b5657SRoger Quadros P0_Q3_BUFFER_OFFSET, 66*a99b5657SRoger Quadros HOST_QUEUE_DESC_OFFSET + 16, 67*a99b5657SRoger Quadros P0_Q3_BD_OFFSET, 68*a99b5657SRoger Quadros P0_Q3_BD_OFFSET + ((HOST_QUEUE_3_SIZE - 1) * BD_SIZE), 69*a99b5657SRoger Quadros }, 70*a99b5657SRoger Quadros [PRUETH_QUEUE4] = { 71*a99b5657SRoger Quadros P0_Q4_BUFFER_OFFSET, 72*a99b5657SRoger Quadros HOST_QUEUE_DESC_OFFSET + 24, 73*a99b5657SRoger Quadros P0_Q4_BD_OFFSET, 74*a99b5657SRoger Quadros P0_Q4_BD_OFFSET + ((HOST_QUEUE_4_SIZE - 1) * BD_SIZE), 75*a99b5657SRoger Quadros }, 76*a99b5657SRoger Quadros }, 77*a99b5657SRoger Quadros [PRUETH_PORT_QUEUE_MII0] = { 78*a99b5657SRoger Quadros [PRUETH_QUEUE1] = { 79*a99b5657SRoger Quadros P1_Q1_BUFFER_OFFSET, 80*a99b5657SRoger Quadros P1_Q1_BUFFER_OFFSET + ((QUEUE_1_SIZE - 1) * 81*a99b5657SRoger Quadros ICSS_BLOCK_SIZE), 82*a99b5657SRoger Quadros P1_Q1_BD_OFFSET, 83*a99b5657SRoger Quadros P1_Q1_BD_OFFSET + ((QUEUE_1_SIZE - 1) * BD_SIZE), 84*a99b5657SRoger Quadros }, 85*a99b5657SRoger Quadros [PRUETH_QUEUE2] = { 86*a99b5657SRoger Quadros P1_Q2_BUFFER_OFFSET, 87*a99b5657SRoger Quadros P1_Q2_BUFFER_OFFSET + ((QUEUE_2_SIZE - 1) * 88*a99b5657SRoger Quadros ICSS_BLOCK_SIZE), 89*a99b5657SRoger Quadros P1_Q2_BD_OFFSET, 90*a99b5657SRoger Quadros P1_Q2_BD_OFFSET + ((QUEUE_2_SIZE - 1) * BD_SIZE), 91*a99b5657SRoger Quadros }, 92*a99b5657SRoger Quadros [PRUETH_QUEUE3] = { 93*a99b5657SRoger Quadros P1_Q3_BUFFER_OFFSET, 94*a99b5657SRoger Quadros P1_Q3_BUFFER_OFFSET + ((QUEUE_3_SIZE - 1) * 95*a99b5657SRoger Quadros ICSS_BLOCK_SIZE), 96*a99b5657SRoger Quadros P1_Q3_BD_OFFSET, 97*a99b5657SRoger Quadros P1_Q3_BD_OFFSET + ((QUEUE_3_SIZE - 1) * BD_SIZE), 98*a99b5657SRoger Quadros }, 99*a99b5657SRoger Quadros [PRUETH_QUEUE4] = { 100*a99b5657SRoger Quadros P1_Q4_BUFFER_OFFSET, 101*a99b5657SRoger Quadros P1_Q4_BUFFER_OFFSET + ((QUEUE_4_SIZE - 1) * 102*a99b5657SRoger Quadros ICSS_BLOCK_SIZE), 103*a99b5657SRoger Quadros P1_Q4_BD_OFFSET, 104*a99b5657SRoger Quadros P1_Q4_BD_OFFSET + ((QUEUE_4_SIZE - 1) * BD_SIZE), 105*a99b5657SRoger Quadros }, 106*a99b5657SRoger Quadros }, 107*a99b5657SRoger Quadros [PRUETH_PORT_QUEUE_MII1] = { 108*a99b5657SRoger Quadros [PRUETH_QUEUE1] = { 109*a99b5657SRoger Quadros P2_Q1_BUFFER_OFFSET, 110*a99b5657SRoger Quadros P2_Q1_BUFFER_OFFSET + ((QUEUE_1_SIZE - 1) * 111*a99b5657SRoger Quadros ICSS_BLOCK_SIZE), 112*a99b5657SRoger Quadros P2_Q1_BD_OFFSET, 113*a99b5657SRoger Quadros P2_Q1_BD_OFFSET + ((QUEUE_1_SIZE - 1) * BD_SIZE), 114*a99b5657SRoger Quadros }, 115*a99b5657SRoger Quadros [PRUETH_QUEUE2] = { 116*a99b5657SRoger Quadros P2_Q2_BUFFER_OFFSET, 117*a99b5657SRoger Quadros P2_Q2_BUFFER_OFFSET + ((QUEUE_2_SIZE - 1) * 118*a99b5657SRoger Quadros ICSS_BLOCK_SIZE), 119*a99b5657SRoger Quadros P2_Q2_BD_OFFSET, 120*a99b5657SRoger Quadros P2_Q2_BD_OFFSET + ((QUEUE_2_SIZE - 1) * BD_SIZE), 121*a99b5657SRoger Quadros }, 122*a99b5657SRoger Quadros [PRUETH_QUEUE3] = { 123*a99b5657SRoger Quadros P2_Q3_BUFFER_OFFSET, 124*a99b5657SRoger Quadros P2_Q3_BUFFER_OFFSET + ((QUEUE_3_SIZE - 1) * 125*a99b5657SRoger Quadros ICSS_BLOCK_SIZE), 126*a99b5657SRoger Quadros P2_Q3_BD_OFFSET, 127*a99b5657SRoger Quadros P2_Q3_BD_OFFSET + ((QUEUE_3_SIZE - 1) * BD_SIZE), 128*a99b5657SRoger Quadros }, 129*a99b5657SRoger Quadros [PRUETH_QUEUE4] = { 130*a99b5657SRoger Quadros P2_Q4_BUFFER_OFFSET, 131*a99b5657SRoger Quadros P2_Q4_BUFFER_OFFSET + ((QUEUE_4_SIZE - 1) * 132*a99b5657SRoger Quadros ICSS_BLOCK_SIZE), 133*a99b5657SRoger Quadros P2_Q4_BD_OFFSET, 134*a99b5657SRoger Quadros P2_Q4_BD_OFFSET + ((QUEUE_4_SIZE - 1) * BD_SIZE), 135*a99b5657SRoger Quadros }, 136*a99b5657SRoger Quadros }, 137*a99b5657SRoger Quadros }; 138*a99b5657SRoger Quadros 139*a99b5657SRoger Quadros static const struct prueth_queue_desc queue_descs[][NUM_QUEUES] = { 140*a99b5657SRoger Quadros [PRUETH_PORT_QUEUE_HOST] = { 141*a99b5657SRoger Quadros { .rd_ptr = P0_Q1_BD_OFFSET, .wr_ptr = P0_Q1_BD_OFFSET, }, 142*a99b5657SRoger Quadros { .rd_ptr = P0_Q2_BD_OFFSET, .wr_ptr = P0_Q2_BD_OFFSET, }, 143*a99b5657SRoger Quadros { .rd_ptr = P0_Q3_BD_OFFSET, .wr_ptr = P0_Q3_BD_OFFSET, }, 144*a99b5657SRoger Quadros { .rd_ptr = P0_Q4_BD_OFFSET, .wr_ptr = P0_Q4_BD_OFFSET, }, 145*a99b5657SRoger Quadros }, 146*a99b5657SRoger Quadros [PRUETH_PORT_QUEUE_MII0] = { 147*a99b5657SRoger Quadros { .rd_ptr = P1_Q1_BD_OFFSET, .wr_ptr = P1_Q1_BD_OFFSET, }, 148*a99b5657SRoger Quadros { .rd_ptr = P1_Q2_BD_OFFSET, .wr_ptr = P1_Q2_BD_OFFSET, }, 149*a99b5657SRoger Quadros { .rd_ptr = P1_Q3_BD_OFFSET, .wr_ptr = P1_Q3_BD_OFFSET, }, 150*a99b5657SRoger Quadros { .rd_ptr = P1_Q4_BD_OFFSET, .wr_ptr = P1_Q4_BD_OFFSET, }, 151*a99b5657SRoger Quadros }, 152*a99b5657SRoger Quadros [PRUETH_PORT_QUEUE_MII1] = { 153*a99b5657SRoger Quadros { .rd_ptr = P2_Q1_BD_OFFSET, .wr_ptr = P2_Q1_BD_OFFSET, }, 154*a99b5657SRoger Quadros { .rd_ptr = P2_Q2_BD_OFFSET, .wr_ptr = P2_Q2_BD_OFFSET, }, 155*a99b5657SRoger Quadros { .rd_ptr = P2_Q3_BD_OFFSET, .wr_ptr = P2_Q3_BD_OFFSET, }, 156*a99b5657SRoger Quadros { .rd_ptr = P2_Q4_BD_OFFSET, .wr_ptr = P2_Q4_BD_OFFSET, }, 157*a99b5657SRoger Quadros } 158*a99b5657SRoger Quadros }; 159*a99b5657SRoger Quadros 160*a99b5657SRoger Quadros static void icssm_prueth_hostconfig(struct prueth *prueth) 161*a99b5657SRoger Quadros { 162*a99b5657SRoger Quadros void __iomem *sram_base = prueth->mem[PRUETH_MEM_SHARED_RAM].va; 163*a99b5657SRoger Quadros void __iomem *sram; 164*a99b5657SRoger Quadros 165*a99b5657SRoger Quadros /* queue size lookup table */ 166*a99b5657SRoger Quadros sram = sram_base + HOST_QUEUE_SIZE_ADDR; 167*a99b5657SRoger Quadros writew(HOST_QUEUE_1_SIZE, sram); 168*a99b5657SRoger Quadros writew(HOST_QUEUE_2_SIZE, sram + 2); 169*a99b5657SRoger Quadros writew(HOST_QUEUE_3_SIZE, sram + 4); 170*a99b5657SRoger Quadros writew(HOST_QUEUE_4_SIZE, sram + 6); 171*a99b5657SRoger Quadros 172*a99b5657SRoger Quadros /* queue information table */ 173*a99b5657SRoger Quadros sram = sram_base + HOST_Q1_RX_CONTEXT_OFFSET; 174*a99b5657SRoger Quadros memcpy_toio(sram, queue_infos[PRUETH_PORT_QUEUE_HOST], 175*a99b5657SRoger Quadros sizeof(queue_infos[PRUETH_PORT_QUEUE_HOST])); 176*a99b5657SRoger Quadros 177*a99b5657SRoger Quadros /* buffer offset table */ 178*a99b5657SRoger Quadros sram = sram_base + HOST_QUEUE_OFFSET_ADDR; 179*a99b5657SRoger Quadros writew(P0_Q1_BUFFER_OFFSET, sram); 180*a99b5657SRoger Quadros writew(P0_Q2_BUFFER_OFFSET, sram + 2); 181*a99b5657SRoger Quadros writew(P0_Q3_BUFFER_OFFSET, sram + 4); 182*a99b5657SRoger Quadros writew(P0_Q4_BUFFER_OFFSET, sram + 6); 183*a99b5657SRoger Quadros 184*a99b5657SRoger Quadros /* buffer descriptor offset table*/ 185*a99b5657SRoger Quadros sram = sram_base + HOST_QUEUE_DESCRIPTOR_OFFSET_ADDR; 186*a99b5657SRoger Quadros writew(P0_Q1_BD_OFFSET, sram); 187*a99b5657SRoger Quadros writew(P0_Q2_BD_OFFSET, sram + 2); 188*a99b5657SRoger Quadros writew(P0_Q3_BD_OFFSET, sram + 4); 189*a99b5657SRoger Quadros writew(P0_Q4_BD_OFFSET, sram + 6); 190*a99b5657SRoger Quadros 191*a99b5657SRoger Quadros /* queue table */ 192*a99b5657SRoger Quadros sram = sram_base + HOST_QUEUE_DESC_OFFSET; 193*a99b5657SRoger Quadros memcpy_toio(sram, queue_descs[PRUETH_PORT_QUEUE_HOST], 194*a99b5657SRoger Quadros sizeof(queue_descs[PRUETH_PORT_QUEUE_HOST])); 195*a99b5657SRoger Quadros } 196*a99b5657SRoger Quadros 197*a99b5657SRoger Quadros static void icssm_prueth_mii_init(struct prueth *prueth) 198*a99b5657SRoger Quadros { 199*a99b5657SRoger Quadros struct regmap *mii_rt; 200*a99b5657SRoger Quadros u32 rxcfg_reg, rxcfg; 201*a99b5657SRoger Quadros u32 txcfg_reg, txcfg; 202*a99b5657SRoger Quadros 203*a99b5657SRoger Quadros mii_rt = prueth->mii_rt; 204*a99b5657SRoger Quadros 205*a99b5657SRoger Quadros rxcfg = PRUSS_MII_RT_RXCFG_RX_ENABLE | 206*a99b5657SRoger Quadros PRUSS_MII_RT_RXCFG_RX_DATA_RDY_MODE_DIS | 207*a99b5657SRoger Quadros PRUSS_MII_RT_RXCFG_RX_L2_EN | 208*a99b5657SRoger Quadros PRUSS_MII_RT_RXCFG_RX_CUT_PREAMBLE | 209*a99b5657SRoger Quadros PRUSS_MII_RT_RXCFG_RX_L2_EOF_SCLR_DIS; 210*a99b5657SRoger Quadros 211*a99b5657SRoger Quadros /* Configuration of Port 0 Rx */ 212*a99b5657SRoger Quadros rxcfg_reg = PRUSS_MII_RT_RXCFG0; 213*a99b5657SRoger Quadros 214*a99b5657SRoger Quadros regmap_write(mii_rt, rxcfg_reg, rxcfg); 215*a99b5657SRoger Quadros 216*a99b5657SRoger Quadros /* Configuration of Port 1 Rx */ 217*a99b5657SRoger Quadros rxcfg_reg = PRUSS_MII_RT_RXCFG1; 218*a99b5657SRoger Quadros 219*a99b5657SRoger Quadros rxcfg |= PRUSS_MII_RT_RXCFG_RX_MUX_SEL; 220*a99b5657SRoger Quadros 221*a99b5657SRoger Quadros regmap_write(mii_rt, rxcfg_reg, rxcfg); 222*a99b5657SRoger Quadros 223*a99b5657SRoger Quadros txcfg = PRUSS_MII_RT_TXCFG_TX_ENABLE | 224*a99b5657SRoger Quadros PRUSS_MII_RT_TXCFG_TX_AUTO_PREAMBLE | 225*a99b5657SRoger Quadros PRUSS_MII_RT_TXCFG_TX_32_MODE_EN | 226*a99b5657SRoger Quadros (TX_START_DELAY << PRUSS_MII_RT_TXCFG_TX_START_DELAY_SHIFT) | 227*a99b5657SRoger Quadros (TX_CLK_DELAY_100M << PRUSS_MII_RT_TXCFG_TX_CLK_DELAY_SHIFT); 228*a99b5657SRoger Quadros 229*a99b5657SRoger Quadros /* Configuration of Port 0 Tx */ 230*a99b5657SRoger Quadros txcfg_reg = PRUSS_MII_RT_TXCFG0; 231*a99b5657SRoger Quadros 232*a99b5657SRoger Quadros regmap_write(mii_rt, txcfg_reg, txcfg); 233*a99b5657SRoger Quadros 234*a99b5657SRoger Quadros txcfg |= PRUSS_MII_RT_TXCFG_TX_MUX_SEL; 235*a99b5657SRoger Quadros 236*a99b5657SRoger Quadros /* Configuration of Port 1 Tx */ 237*a99b5657SRoger Quadros txcfg_reg = PRUSS_MII_RT_TXCFG1; 238*a99b5657SRoger Quadros 239*a99b5657SRoger Quadros regmap_write(mii_rt, txcfg_reg, txcfg); 240*a99b5657SRoger Quadros 241*a99b5657SRoger Quadros txcfg_reg = PRUSS_MII_RT_RX_FRMS0; 242*a99b5657SRoger Quadros 243*a99b5657SRoger Quadros /* Min frame length should be set to 64 to allow receive of standard 244*a99b5657SRoger Quadros * Ethernet frames such as PTP, LLDP that will not have the tag/rct. 245*a99b5657SRoger Quadros * Actual size written to register is size - 1 per TRM. This also 246*a99b5657SRoger Quadros * includes CRC/FCS. 247*a99b5657SRoger Quadros */ 248*a99b5657SRoger Quadros txcfg = FIELD_PREP(PRUSS_MII_RT_RX_FRMS_MIN_FRM_MASK, 249*a99b5657SRoger Quadros (PRUSS_MII_RT_RX_FRMS_MIN_FRM - 1)); 250*a99b5657SRoger Quadros 251*a99b5657SRoger Quadros /* For EMAC, set Max frame size to 1528 i.e size with VLAN. 252*a99b5657SRoger Quadros * Actual size written to register is size - 1 as per TRM. 253*a99b5657SRoger Quadros * Since driver support run time change of protocol, driver 254*a99b5657SRoger Quadros * must overwrite the values based on Ethernet type. 255*a99b5657SRoger Quadros */ 256*a99b5657SRoger Quadros txcfg |= FIELD_PREP(PRUSS_MII_RT_RX_FRMS_MAX_FRM_MASK, 257*a99b5657SRoger Quadros (PRUSS_MII_RT_RX_FRMS_MAX_SUPPORT_EMAC - 1)); 258*a99b5657SRoger Quadros 259*a99b5657SRoger Quadros regmap_write(mii_rt, txcfg_reg, txcfg); 260*a99b5657SRoger Quadros 261*a99b5657SRoger Quadros txcfg_reg = PRUSS_MII_RT_RX_FRMS1; 262*a99b5657SRoger Quadros 263*a99b5657SRoger Quadros regmap_write(mii_rt, txcfg_reg, txcfg); 264*a99b5657SRoger Quadros } 265*a99b5657SRoger Quadros 266*a99b5657SRoger Quadros static void icssm_prueth_clearmem(struct prueth *prueth, enum prueth_mem region) 267*a99b5657SRoger Quadros { 268*a99b5657SRoger Quadros memset_io(prueth->mem[region].va, 0, prueth->mem[region].size); 269*a99b5657SRoger Quadros } 270*a99b5657SRoger Quadros 271*a99b5657SRoger Quadros static void icssm_prueth_hostinit(struct prueth *prueth) 272*a99b5657SRoger Quadros { 273*a99b5657SRoger Quadros /* Clear shared RAM */ 274*a99b5657SRoger Quadros icssm_prueth_clearmem(prueth, PRUETH_MEM_SHARED_RAM); 275*a99b5657SRoger Quadros 276*a99b5657SRoger Quadros /* Clear OCMC RAM */ 277*a99b5657SRoger Quadros icssm_prueth_clearmem(prueth, PRUETH_MEM_OCMC); 278*a99b5657SRoger Quadros 279*a99b5657SRoger Quadros /* Clear data RAMs */ 280*a99b5657SRoger Quadros if (prueth->eth_node[PRUETH_MAC0]) 281*a99b5657SRoger Quadros icssm_prueth_clearmem(prueth, PRUETH_MEM_DRAM0); 282*a99b5657SRoger Quadros if (prueth->eth_node[PRUETH_MAC1]) 283*a99b5657SRoger Quadros icssm_prueth_clearmem(prueth, PRUETH_MEM_DRAM1); 284*a99b5657SRoger Quadros 285*a99b5657SRoger Quadros /* Initialize host queues in shared RAM */ 286*a99b5657SRoger Quadros icssm_prueth_hostconfig(prueth); 287*a99b5657SRoger Quadros 288*a99b5657SRoger Quadros /* Configure MII_RT */ 289*a99b5657SRoger Quadros icssm_prueth_mii_init(prueth); 290*a99b5657SRoger Quadros } 291*a99b5657SRoger Quadros 292*a99b5657SRoger Quadros /* This function initialize the driver in EMAC or HSR or PRP mode 293*a99b5657SRoger Quadros * based on eth_type 294*a99b5657SRoger Quadros */ 295*a99b5657SRoger Quadros static void icssm_prueth_init_ethernet_mode(struct prueth *prueth) 296*a99b5657SRoger Quadros { 297*a99b5657SRoger Quadros icssm_prueth_hostinit(prueth); 298*a99b5657SRoger Quadros } 299*a99b5657SRoger Quadros 300*a99b5657SRoger Quadros static int icssm_prueth_emac_config(struct prueth_emac *emac) 301*a99b5657SRoger Quadros { 302*a99b5657SRoger Quadros struct prueth *prueth = emac->prueth; 303*a99b5657SRoger Quadros u32 sharedramaddr, ocmcaddr; 304*a99b5657SRoger Quadros void __iomem *dram_base; 305*a99b5657SRoger Quadros void __iomem *mac_addr; 306*a99b5657SRoger Quadros void __iomem *dram; 307*a99b5657SRoger Quadros 308*a99b5657SRoger Quadros /* PRU needs local shared RAM address for C28 */ 309*a99b5657SRoger Quadros sharedramaddr = ICSS_LOCAL_SHARED_RAM; 310*a99b5657SRoger Quadros /* PRU needs real global OCMC address for C30*/ 311*a99b5657SRoger Quadros ocmcaddr = (u32)prueth->mem[PRUETH_MEM_OCMC].pa; 312*a99b5657SRoger Quadros 313*a99b5657SRoger Quadros /* Clear data RAM */ 314*a99b5657SRoger Quadros icssm_prueth_clearmem(prueth, emac->dram); 315*a99b5657SRoger Quadros 316*a99b5657SRoger Quadros dram_base = prueth->mem[emac->dram].va; 317*a99b5657SRoger Quadros 318*a99b5657SRoger Quadros /* setup mac address */ 319*a99b5657SRoger Quadros mac_addr = dram_base + PORT_MAC_ADDR; 320*a99b5657SRoger Quadros memcpy_toio(mac_addr, emac->mac_addr, 6); 321*a99b5657SRoger Quadros 322*a99b5657SRoger Quadros /* queue information table */ 323*a99b5657SRoger Quadros dram = dram_base + TX_CONTEXT_Q1_OFFSET_ADDR; 324*a99b5657SRoger Quadros memcpy_toio(dram, queue_infos[emac->port_id], 325*a99b5657SRoger Quadros sizeof(queue_infos[emac->port_id])); 326*a99b5657SRoger Quadros 327*a99b5657SRoger Quadros /* queue table */ 328*a99b5657SRoger Quadros dram = dram_base + PORT_QUEUE_DESC_OFFSET; 329*a99b5657SRoger Quadros memcpy_toio(dram, queue_descs[emac->port_id], 330*a99b5657SRoger Quadros sizeof(queue_descs[emac->port_id])); 331*a99b5657SRoger Quadros 332*a99b5657SRoger Quadros /* Set in constant table C28 of PRU0 to ICSS Shared memory */ 333*a99b5657SRoger Quadros pru_rproc_set_ctable(emac->pru, PRU_C28, sharedramaddr); 334*a99b5657SRoger Quadros 335*a99b5657SRoger Quadros /* Set in constant table C30 of PRU0 to OCMC memory */ 336*a99b5657SRoger Quadros pru_rproc_set_ctable(emac->pru, PRU_C30, ocmcaddr); 337*a99b5657SRoger Quadros 338*a99b5657SRoger Quadros return 0; 339*a99b5657SRoger Quadros } 340511f6c1aSRoger Quadros 341511f6c1aSRoger Quadros /* called back by PHY layer if there is change in link state of hw port*/ 342511f6c1aSRoger Quadros static void icssm_emac_adjust_link(struct net_device *ndev) 343511f6c1aSRoger Quadros { 344511f6c1aSRoger Quadros struct prueth_emac *emac = netdev_priv(ndev); 345511f6c1aSRoger Quadros struct phy_device *phydev = emac->phydev; 346511f6c1aSRoger Quadros bool new_state = false; 347511f6c1aSRoger Quadros unsigned long flags; 348511f6c1aSRoger Quadros 349511f6c1aSRoger Quadros spin_lock_irqsave(&emac->lock, flags); 350511f6c1aSRoger Quadros 351511f6c1aSRoger Quadros if (phydev->link) { 352511f6c1aSRoger Quadros /* check the mode of operation */ 353511f6c1aSRoger Quadros if (phydev->duplex != emac->duplex) { 354511f6c1aSRoger Quadros new_state = true; 355511f6c1aSRoger Quadros emac->duplex = phydev->duplex; 356511f6c1aSRoger Quadros } 357511f6c1aSRoger Quadros if (phydev->speed != emac->speed) { 358511f6c1aSRoger Quadros new_state = true; 359511f6c1aSRoger Quadros emac->speed = phydev->speed; 360511f6c1aSRoger Quadros } 361511f6c1aSRoger Quadros if (!emac->link) { 362511f6c1aSRoger Quadros new_state = true; 363511f6c1aSRoger Quadros emac->link = 1; 364511f6c1aSRoger Quadros } 365511f6c1aSRoger Quadros } else if (emac->link) { 366511f6c1aSRoger Quadros new_state = true; 367511f6c1aSRoger Quadros emac->link = 0; 368511f6c1aSRoger Quadros } 369511f6c1aSRoger Quadros 370511f6c1aSRoger Quadros if (new_state) 371511f6c1aSRoger Quadros phy_print_status(phydev); 372511f6c1aSRoger Quadros 373511f6c1aSRoger Quadros if (emac->link) { 374511f6c1aSRoger Quadros /* reactivate the transmit queue if it is stopped */ 375511f6c1aSRoger Quadros if (netif_running(ndev) && netif_queue_stopped(ndev)) 376511f6c1aSRoger Quadros netif_wake_queue(ndev); 377511f6c1aSRoger Quadros } else { 378511f6c1aSRoger Quadros if (!netif_queue_stopped(ndev)) 379511f6c1aSRoger Quadros netif_stop_queue(ndev); 380511f6c1aSRoger Quadros } 381511f6c1aSRoger Quadros 382511f6c1aSRoger Quadros spin_unlock_irqrestore(&emac->lock, flags); 383511f6c1aSRoger Quadros } 384511f6c1aSRoger Quadros 385511f6c1aSRoger Quadros static int icssm_emac_set_boot_pru(struct prueth_emac *emac, 386511f6c1aSRoger Quadros struct net_device *ndev) 387511f6c1aSRoger Quadros { 388511f6c1aSRoger Quadros const struct prueth_firmware *pru_firmwares; 389511f6c1aSRoger Quadros struct prueth *prueth = emac->prueth; 390511f6c1aSRoger Quadros const char *fw_name; 391511f6c1aSRoger Quadros int ret; 392511f6c1aSRoger Quadros 393511f6c1aSRoger Quadros pru_firmwares = &prueth->fw_data->fw_pru[emac->port_id - 1]; 394511f6c1aSRoger Quadros fw_name = pru_firmwares->fw_name[prueth->eth_type]; 395511f6c1aSRoger Quadros if (!fw_name) { 396511f6c1aSRoger Quadros netdev_err(ndev, "eth_type %d not supported\n", 397511f6c1aSRoger Quadros prueth->eth_type); 398511f6c1aSRoger Quadros return -ENODEV; 399511f6c1aSRoger Quadros } 400511f6c1aSRoger Quadros 401511f6c1aSRoger Quadros ret = rproc_set_firmware(emac->pru, fw_name); 402511f6c1aSRoger Quadros if (ret) { 403511f6c1aSRoger Quadros netdev_err(ndev, "failed to set %s firmware: %d\n", 404511f6c1aSRoger Quadros fw_name, ret); 405511f6c1aSRoger Quadros return ret; 406511f6c1aSRoger Quadros } 407511f6c1aSRoger Quadros 408511f6c1aSRoger Quadros ret = rproc_boot(emac->pru); 409511f6c1aSRoger Quadros if (ret) { 410511f6c1aSRoger Quadros netdev_err(ndev, "failed to boot %s firmware: %d\n", 411511f6c1aSRoger Quadros fw_name, ret); 412511f6c1aSRoger Quadros return ret; 413511f6c1aSRoger Quadros } 414511f6c1aSRoger Quadros 415511f6c1aSRoger Quadros return ret; 416511f6c1aSRoger Quadros } 417511f6c1aSRoger Quadros 418511f6c1aSRoger Quadros /** 419511f6c1aSRoger Quadros * icssm_emac_ndo_open - EMAC device open 420511f6c1aSRoger Quadros * @ndev: network adapter device 421511f6c1aSRoger Quadros * 422511f6c1aSRoger Quadros * Called when system wants to start the interface. 423511f6c1aSRoger Quadros * 424511f6c1aSRoger Quadros * Return: 0 for a successful open, or appropriate error code 425511f6c1aSRoger Quadros */ 426511f6c1aSRoger Quadros static int icssm_emac_ndo_open(struct net_device *ndev) 427511f6c1aSRoger Quadros { 428511f6c1aSRoger Quadros struct prueth_emac *emac = netdev_priv(ndev); 429*a99b5657SRoger Quadros struct prueth *prueth = emac->prueth; 430511f6c1aSRoger Quadros int ret; 431511f6c1aSRoger Quadros 432*a99b5657SRoger Quadros /* set h/w MAC as user might have re-configured */ 433*a99b5657SRoger Quadros ether_addr_copy(emac->mac_addr, ndev->dev_addr); 434*a99b5657SRoger Quadros 435*a99b5657SRoger Quadros if (!prueth->emac_configured) 436*a99b5657SRoger Quadros icssm_prueth_init_ethernet_mode(prueth); 437*a99b5657SRoger Quadros 438*a99b5657SRoger Quadros icssm_prueth_emac_config(emac); 439*a99b5657SRoger Quadros 440511f6c1aSRoger Quadros ret = icssm_emac_set_boot_pru(emac, ndev); 441511f6c1aSRoger Quadros if (ret) 442511f6c1aSRoger Quadros return ret; 443511f6c1aSRoger Quadros 444511f6c1aSRoger Quadros /* start PHY */ 445511f6c1aSRoger Quadros phy_start(emac->phydev); 446*a99b5657SRoger Quadros prueth->emac_configured |= BIT(emac->port_id); 447511f6c1aSRoger Quadros return 0; 448511f6c1aSRoger Quadros } 449511f6c1aSRoger Quadros 450511f6c1aSRoger Quadros /** 451511f6c1aSRoger Quadros * icssm_emac_ndo_stop - EMAC device stop 452511f6c1aSRoger Quadros * @ndev: network adapter device 453511f6c1aSRoger Quadros * 454511f6c1aSRoger Quadros * Called when system wants to stop or down the interface. 455511f6c1aSRoger Quadros * 456511f6c1aSRoger Quadros * Return: Always 0 (Success) 457511f6c1aSRoger Quadros */ 458511f6c1aSRoger Quadros static int icssm_emac_ndo_stop(struct net_device *ndev) 459511f6c1aSRoger Quadros { 460511f6c1aSRoger Quadros struct prueth_emac *emac = netdev_priv(ndev); 461511f6c1aSRoger Quadros 462511f6c1aSRoger Quadros /* stop PHY */ 463511f6c1aSRoger Quadros phy_stop(emac->phydev); 464511f6c1aSRoger Quadros 465511f6c1aSRoger Quadros rproc_shutdown(emac->pru); 466511f6c1aSRoger Quadros 467511f6c1aSRoger Quadros return 0; 468511f6c1aSRoger Quadros } 469511f6c1aSRoger Quadros 470511f6c1aSRoger Quadros static const struct net_device_ops emac_netdev_ops = { 471511f6c1aSRoger Quadros .ndo_open = icssm_emac_ndo_open, 472511f6c1aSRoger Quadros .ndo_stop = icssm_emac_ndo_stop, 473511f6c1aSRoger Quadros }; 474511f6c1aSRoger Quadros 475511f6c1aSRoger Quadros /* get emac_port corresponding to eth_node name */ 476511f6c1aSRoger Quadros static int icssm_prueth_node_port(struct device_node *eth_node) 477511f6c1aSRoger Quadros { 478511f6c1aSRoger Quadros u32 port_id; 479511f6c1aSRoger Quadros int ret; 480511f6c1aSRoger Quadros 481511f6c1aSRoger Quadros ret = of_property_read_u32(eth_node, "reg", &port_id); 482511f6c1aSRoger Quadros if (ret) 483511f6c1aSRoger Quadros return ret; 484511f6c1aSRoger Quadros 485511f6c1aSRoger Quadros if (port_id == 0) 486511f6c1aSRoger Quadros return PRUETH_PORT_MII0; 487511f6c1aSRoger Quadros else if (port_id == 1) 488511f6c1aSRoger Quadros return PRUETH_PORT_MII1; 489511f6c1aSRoger Quadros else 490511f6c1aSRoger Quadros return PRUETH_PORT_INVALID; 491511f6c1aSRoger Quadros } 492511f6c1aSRoger Quadros 493511f6c1aSRoger Quadros /* get MAC instance corresponding to eth_node name */ 494511f6c1aSRoger Quadros static int icssm_prueth_node_mac(struct device_node *eth_node) 495511f6c1aSRoger Quadros { 496511f6c1aSRoger Quadros u32 port_id; 497511f6c1aSRoger Quadros int ret; 498511f6c1aSRoger Quadros 499511f6c1aSRoger Quadros ret = of_property_read_u32(eth_node, "reg", &port_id); 500511f6c1aSRoger Quadros if (ret) 501511f6c1aSRoger Quadros return ret; 502511f6c1aSRoger Quadros 503511f6c1aSRoger Quadros if (port_id == 0) 504511f6c1aSRoger Quadros return PRUETH_MAC0; 505511f6c1aSRoger Quadros else if (port_id == 1) 506511f6c1aSRoger Quadros return PRUETH_MAC1; 507511f6c1aSRoger Quadros else 508511f6c1aSRoger Quadros return PRUETH_MAC_INVALID; 509511f6c1aSRoger Quadros } 510511f6c1aSRoger Quadros 511511f6c1aSRoger Quadros static int icssm_prueth_netdev_init(struct prueth *prueth, 512511f6c1aSRoger Quadros struct device_node *eth_node) 513511f6c1aSRoger Quadros { 514511f6c1aSRoger Quadros struct prueth_emac *emac; 515511f6c1aSRoger Quadros struct net_device *ndev; 516511f6c1aSRoger Quadros enum prueth_port port; 517511f6c1aSRoger Quadros enum prueth_mac mac; 518511f6c1aSRoger Quadros int ret; 519511f6c1aSRoger Quadros 520511f6c1aSRoger Quadros port = icssm_prueth_node_port(eth_node); 521511f6c1aSRoger Quadros if (port == PRUETH_PORT_INVALID) 522511f6c1aSRoger Quadros return -EINVAL; 523511f6c1aSRoger Quadros 524511f6c1aSRoger Quadros mac = icssm_prueth_node_mac(eth_node); 525511f6c1aSRoger Quadros if (mac == PRUETH_MAC_INVALID) 526511f6c1aSRoger Quadros return -EINVAL; 527511f6c1aSRoger Quadros 528511f6c1aSRoger Quadros ndev = devm_alloc_etherdev(prueth->dev, sizeof(*emac)); 529511f6c1aSRoger Quadros if (!ndev) 530511f6c1aSRoger Quadros return -ENOMEM; 531511f6c1aSRoger Quadros 532511f6c1aSRoger Quadros SET_NETDEV_DEV(ndev, prueth->dev); 533511f6c1aSRoger Quadros emac = netdev_priv(ndev); 534511f6c1aSRoger Quadros prueth->emac[mac] = emac; 535511f6c1aSRoger Quadros emac->prueth = prueth; 536511f6c1aSRoger Quadros emac->ndev = ndev; 537511f6c1aSRoger Quadros emac->port_id = port; 538511f6c1aSRoger Quadros 539511f6c1aSRoger Quadros /* by default eth_type is EMAC */ 540511f6c1aSRoger Quadros switch (port) { 541511f6c1aSRoger Quadros case PRUETH_PORT_MII0: 542*a99b5657SRoger Quadros emac->dram = PRUETH_MEM_DRAM0; 543511f6c1aSRoger Quadros emac->pru = prueth->pru0; 544511f6c1aSRoger Quadros break; 545511f6c1aSRoger Quadros case PRUETH_PORT_MII1: 546*a99b5657SRoger Quadros emac->dram = PRUETH_MEM_DRAM1; 547511f6c1aSRoger Quadros emac->pru = prueth->pru1; 548511f6c1aSRoger Quadros break; 549511f6c1aSRoger Quadros default: 550511f6c1aSRoger Quadros return -EINVAL; 551511f6c1aSRoger Quadros } 552511f6c1aSRoger Quadros /* get mac address from DT and set private and netdev addr */ 553511f6c1aSRoger Quadros ret = of_get_ethdev_address(eth_node, ndev); 554511f6c1aSRoger Quadros if (!is_valid_ether_addr(ndev->dev_addr)) { 555511f6c1aSRoger Quadros eth_hw_addr_random(ndev); 556511f6c1aSRoger Quadros dev_warn(prueth->dev, "port %d: using random MAC addr: %pM\n", 557511f6c1aSRoger Quadros port, ndev->dev_addr); 558511f6c1aSRoger Quadros } 559511f6c1aSRoger Quadros ether_addr_copy(emac->mac_addr, ndev->dev_addr); 560511f6c1aSRoger Quadros 561511f6c1aSRoger Quadros /* connect PHY */ 562511f6c1aSRoger Quadros emac->phydev = of_phy_get_and_connect(ndev, eth_node, 563511f6c1aSRoger Quadros icssm_emac_adjust_link); 564511f6c1aSRoger Quadros if (!emac->phydev) { 565511f6c1aSRoger Quadros dev_dbg(prueth->dev, "PHY connection failed\n"); 566511f6c1aSRoger Quadros ret = -ENODEV; 567511f6c1aSRoger Quadros goto free; 568511f6c1aSRoger Quadros } 569511f6c1aSRoger Quadros 570511f6c1aSRoger Quadros /* remove unsupported modes */ 571511f6c1aSRoger Quadros phy_remove_link_mode(emac->phydev, ETHTOOL_LINK_MODE_10baseT_Full_BIT); 572511f6c1aSRoger Quadros 573511f6c1aSRoger Quadros phy_remove_link_mode(emac->phydev, ETHTOOL_LINK_MODE_10baseT_Half_BIT); 574511f6c1aSRoger Quadros phy_remove_link_mode(emac->phydev, ETHTOOL_LINK_MODE_100baseT_Half_BIT); 575511f6c1aSRoger Quadros 576511f6c1aSRoger Quadros phy_remove_link_mode(emac->phydev, ETHTOOL_LINK_MODE_Pause_BIT); 577511f6c1aSRoger Quadros phy_remove_link_mode(emac->phydev, ETHTOOL_LINK_MODE_Asym_Pause_BIT); 578511f6c1aSRoger Quadros 579511f6c1aSRoger Quadros ndev->dev.of_node = eth_node; 580511f6c1aSRoger Quadros ndev->netdev_ops = &emac_netdev_ops; 581511f6c1aSRoger Quadros 582511f6c1aSRoger Quadros return 0; 583511f6c1aSRoger Quadros free: 584511f6c1aSRoger Quadros emac->ndev = NULL; 585511f6c1aSRoger Quadros prueth->emac[mac] = NULL; 586511f6c1aSRoger Quadros 587511f6c1aSRoger Quadros return ret; 588511f6c1aSRoger Quadros } 589511f6c1aSRoger Quadros 590511f6c1aSRoger Quadros static void icssm_prueth_netdev_exit(struct prueth *prueth, 591511f6c1aSRoger Quadros struct device_node *eth_node) 592511f6c1aSRoger Quadros { 593511f6c1aSRoger Quadros struct prueth_emac *emac; 594511f6c1aSRoger Quadros enum prueth_mac mac; 595511f6c1aSRoger Quadros 596511f6c1aSRoger Quadros mac = icssm_prueth_node_mac(eth_node); 597511f6c1aSRoger Quadros if (mac == PRUETH_MAC_INVALID) 598511f6c1aSRoger Quadros return; 599511f6c1aSRoger Quadros 600511f6c1aSRoger Quadros emac = prueth->emac[mac]; 601511f6c1aSRoger Quadros if (!emac) 602511f6c1aSRoger Quadros return; 603511f6c1aSRoger Quadros 604511f6c1aSRoger Quadros phy_disconnect(emac->phydev); 605511f6c1aSRoger Quadros 606511f6c1aSRoger Quadros prueth->emac[mac] = NULL; 607511f6c1aSRoger Quadros } 608511f6c1aSRoger Quadros 609511f6c1aSRoger Quadros static int icssm_prueth_probe(struct platform_device *pdev) 610511f6c1aSRoger Quadros { 611511f6c1aSRoger Quadros struct device_node *eth0_node = NULL, *eth1_node = NULL; 612511f6c1aSRoger Quadros struct device_node *eth_node, *eth_ports_node; 613511f6c1aSRoger Quadros enum pruss_pru_id pruss_id0, pruss_id1; 614511f6c1aSRoger Quadros struct device *dev = &pdev->dev; 615511f6c1aSRoger Quadros struct device_node *np; 616511f6c1aSRoger Quadros struct prueth *prueth; 617*a99b5657SRoger Quadros struct pruss *pruss; 618511f6c1aSRoger Quadros int i, ret; 619511f6c1aSRoger Quadros 620511f6c1aSRoger Quadros np = dev->of_node; 621511f6c1aSRoger Quadros if (!np) 622511f6c1aSRoger Quadros return -ENODEV; /* we don't support non DT */ 623511f6c1aSRoger Quadros 624511f6c1aSRoger Quadros prueth = devm_kzalloc(dev, sizeof(*prueth), GFP_KERNEL); 625511f6c1aSRoger Quadros if (!prueth) 626511f6c1aSRoger Quadros return -ENOMEM; 627511f6c1aSRoger Quadros 628511f6c1aSRoger Quadros platform_set_drvdata(pdev, prueth); 629511f6c1aSRoger Quadros prueth->dev = dev; 630511f6c1aSRoger Quadros prueth->fw_data = device_get_match_data(dev); 631511f6c1aSRoger Quadros 632511f6c1aSRoger Quadros eth_ports_node = of_get_child_by_name(np, "ethernet-ports"); 633511f6c1aSRoger Quadros if (!eth_ports_node) 634511f6c1aSRoger Quadros return -ENOENT; 635511f6c1aSRoger Quadros 636511f6c1aSRoger Quadros for_each_child_of_node(eth_ports_node, eth_node) { 637511f6c1aSRoger Quadros u32 reg; 638511f6c1aSRoger Quadros 639511f6c1aSRoger Quadros if (strcmp(eth_node->name, "ethernet-port")) 640511f6c1aSRoger Quadros continue; 641511f6c1aSRoger Quadros ret = of_property_read_u32(eth_node, "reg", ®); 642511f6c1aSRoger Quadros if (ret < 0) { 643511f6c1aSRoger Quadros dev_err(dev, "%pOF error reading port_id %d\n", 644511f6c1aSRoger Quadros eth_node, ret); 645511f6c1aSRoger Quadros of_node_put(eth_node); 646511f6c1aSRoger Quadros return ret; 647511f6c1aSRoger Quadros } 648511f6c1aSRoger Quadros 649511f6c1aSRoger Quadros of_node_get(eth_node); 650511f6c1aSRoger Quadros 651511f6c1aSRoger Quadros if (reg == 0 && !eth0_node) { 652511f6c1aSRoger Quadros eth0_node = eth_node; 653511f6c1aSRoger Quadros if (!of_device_is_available(eth0_node)) { 654511f6c1aSRoger Quadros of_node_put(eth0_node); 655511f6c1aSRoger Quadros eth0_node = NULL; 656511f6c1aSRoger Quadros } 657511f6c1aSRoger Quadros } else if (reg == 1 && !eth1_node) { 658511f6c1aSRoger Quadros eth1_node = eth_node; 659511f6c1aSRoger Quadros if (!of_device_is_available(eth1_node)) { 660511f6c1aSRoger Quadros of_node_put(eth1_node); 661511f6c1aSRoger Quadros eth1_node = NULL; 662511f6c1aSRoger Quadros } 663511f6c1aSRoger Quadros } else { 664511f6c1aSRoger Quadros if (reg == 0 || reg == 1) 665511f6c1aSRoger Quadros dev_err(dev, "duplicate port reg value: %d\n", 666511f6c1aSRoger Quadros reg); 667511f6c1aSRoger Quadros else 668511f6c1aSRoger Quadros dev_err(dev, "invalid port reg value: %d\n", 669511f6c1aSRoger Quadros reg); 670511f6c1aSRoger Quadros 671511f6c1aSRoger Quadros of_node_put(eth_node); 672511f6c1aSRoger Quadros } 673511f6c1aSRoger Quadros } 674511f6c1aSRoger Quadros 675511f6c1aSRoger Quadros of_node_put(eth_ports_node); 676511f6c1aSRoger Quadros 677511f6c1aSRoger Quadros /* At least one node must be present and available else we fail */ 678511f6c1aSRoger Quadros if (!eth0_node && !eth1_node) { 679511f6c1aSRoger Quadros dev_err(dev, "neither port0 nor port1 node available\n"); 680511f6c1aSRoger Quadros return -ENODEV; 681511f6c1aSRoger Quadros } 682511f6c1aSRoger Quadros 683511f6c1aSRoger Quadros prueth->eth_node[PRUETH_MAC0] = eth0_node; 684511f6c1aSRoger Quadros prueth->eth_node[PRUETH_MAC1] = eth1_node; 685511f6c1aSRoger Quadros 686*a99b5657SRoger Quadros prueth->mii_rt = syscon_regmap_lookup_by_phandle(np, "ti,mii-rt"); 687*a99b5657SRoger Quadros if (IS_ERR(prueth->mii_rt)) { 688*a99b5657SRoger Quadros dev_err(dev, "couldn't get mii-rt syscon regmap\n"); 689*a99b5657SRoger Quadros return -ENODEV; 690*a99b5657SRoger Quadros } 691*a99b5657SRoger Quadros 692511f6c1aSRoger Quadros if (eth0_node) { 693511f6c1aSRoger Quadros prueth->pru0 = pru_rproc_get(np, 0, &pruss_id0); 694511f6c1aSRoger Quadros if (IS_ERR(prueth->pru0)) { 695511f6c1aSRoger Quadros ret = PTR_ERR(prueth->pru0); 696511f6c1aSRoger Quadros dev_err_probe(dev, ret, "unable to get PRU0"); 697511f6c1aSRoger Quadros goto put_pru; 698511f6c1aSRoger Quadros } 699511f6c1aSRoger Quadros } 700511f6c1aSRoger Quadros 701511f6c1aSRoger Quadros if (eth1_node) { 702511f6c1aSRoger Quadros prueth->pru1 = pru_rproc_get(np, 1, &pruss_id1); 703511f6c1aSRoger Quadros if (IS_ERR(prueth->pru1)) { 704511f6c1aSRoger Quadros ret = PTR_ERR(prueth->pru1); 705511f6c1aSRoger Quadros dev_err_probe(dev, ret, "unable to get PRU1"); 706511f6c1aSRoger Quadros goto put_pru; 707511f6c1aSRoger Quadros } 708511f6c1aSRoger Quadros } 709511f6c1aSRoger Quadros 710*a99b5657SRoger Quadros pruss = pruss_get(prueth->pru0 ? prueth->pru0 : prueth->pru1); 711*a99b5657SRoger Quadros if (IS_ERR(pruss)) { 712*a99b5657SRoger Quadros ret = PTR_ERR(pruss); 713*a99b5657SRoger Quadros dev_err(dev, "unable to get pruss handle\n"); 714*a99b5657SRoger Quadros goto put_pru; 715*a99b5657SRoger Quadros } 716*a99b5657SRoger Quadros prueth->pruss = pruss; 717*a99b5657SRoger Quadros 718*a99b5657SRoger Quadros /* Configure PRUSS */ 719*a99b5657SRoger Quadros if (eth0_node) 720*a99b5657SRoger Quadros pruss_cfg_gpimode(pruss, pruss_id0, PRUSS_GPI_MODE_MII); 721*a99b5657SRoger Quadros if (eth1_node) 722*a99b5657SRoger Quadros pruss_cfg_gpimode(pruss, pruss_id1, PRUSS_GPI_MODE_MII); 723*a99b5657SRoger Quadros pruss_cfg_miirt_enable(pruss, true); 724*a99b5657SRoger Quadros pruss_cfg_xfr_enable(pruss, PRU_TYPE_PRU, true); 725*a99b5657SRoger Quadros 726*a99b5657SRoger Quadros /* Get PRUSS mem resources */ 727*a99b5657SRoger Quadros /* OCMC is system resource which we get separately */ 728*a99b5657SRoger Quadros for (i = 0; i < ARRAY_SIZE(pruss_mem_ids); i++) { 729*a99b5657SRoger Quadros /* skip appropriate DRAM if not required */ 730*a99b5657SRoger Quadros if (!eth0_node && i == PRUETH_MEM_DRAM0) 731*a99b5657SRoger Quadros continue; 732*a99b5657SRoger Quadros 733*a99b5657SRoger Quadros if (!eth1_node && i == PRUETH_MEM_DRAM1) 734*a99b5657SRoger Quadros continue; 735*a99b5657SRoger Quadros 736*a99b5657SRoger Quadros ret = pruss_request_mem_region(pruss, pruss_mem_ids[i], 737*a99b5657SRoger Quadros &prueth->mem[i]); 738*a99b5657SRoger Quadros if (ret) { 739*a99b5657SRoger Quadros dev_err(dev, "unable to get PRUSS resource %d: %d\n", 740*a99b5657SRoger Quadros i, ret); 741*a99b5657SRoger Quadros goto put_mem; 742*a99b5657SRoger Quadros } 743*a99b5657SRoger Quadros } 744*a99b5657SRoger Quadros 745*a99b5657SRoger Quadros prueth->sram_pool = of_gen_pool_get(np, "sram", 0); 746*a99b5657SRoger Quadros if (!prueth->sram_pool) { 747*a99b5657SRoger Quadros dev_err(dev, "unable to get SRAM pool\n"); 748*a99b5657SRoger Quadros ret = -ENODEV; 749*a99b5657SRoger Quadros goto put_mem; 750*a99b5657SRoger Quadros } 751*a99b5657SRoger Quadros 752*a99b5657SRoger Quadros prueth->ocmc_ram_size = OCMC_RAM_SIZE; 753*a99b5657SRoger Quadros /* Decreased by 8KB to address the reserved region for AM33x */ 754*a99b5657SRoger Quadros if (prueth->fw_data->driver_data == PRUSS_AM33XX) 755*a99b5657SRoger Quadros prueth->ocmc_ram_size = (SZ_64K - SZ_8K); 756*a99b5657SRoger Quadros 757*a99b5657SRoger Quadros prueth->mem[PRUETH_MEM_OCMC].va = 758*a99b5657SRoger Quadros (void __iomem *)gen_pool_alloc(prueth->sram_pool, 759*a99b5657SRoger Quadros prueth->ocmc_ram_size); 760*a99b5657SRoger Quadros if (!prueth->mem[PRUETH_MEM_OCMC].va) { 761*a99b5657SRoger Quadros dev_err(dev, "unable to allocate OCMC resource\n"); 762*a99b5657SRoger Quadros ret = -ENOMEM; 763*a99b5657SRoger Quadros goto put_mem; 764*a99b5657SRoger Quadros } 765*a99b5657SRoger Quadros prueth->mem[PRUETH_MEM_OCMC].pa = gen_pool_virt_to_phys 766*a99b5657SRoger Quadros (prueth->sram_pool, (unsigned long) 767*a99b5657SRoger Quadros prueth->mem[PRUETH_MEM_OCMC].va); 768*a99b5657SRoger Quadros prueth->mem[PRUETH_MEM_OCMC].size = prueth->ocmc_ram_size; 769*a99b5657SRoger Quadros dev_dbg(dev, "ocmc: pa %pa va %p size %#zx\n", 770*a99b5657SRoger Quadros &prueth->mem[PRUETH_MEM_OCMC].pa, 771*a99b5657SRoger Quadros prueth->mem[PRUETH_MEM_OCMC].va, 772*a99b5657SRoger Quadros prueth->mem[PRUETH_MEM_OCMC].size); 773*a99b5657SRoger Quadros 774511f6c1aSRoger Quadros /* setup netdev interfaces */ 775511f6c1aSRoger Quadros if (eth0_node) { 776511f6c1aSRoger Quadros ret = icssm_prueth_netdev_init(prueth, eth0_node); 777511f6c1aSRoger Quadros if (ret) { 778511f6c1aSRoger Quadros if (ret != -EPROBE_DEFER) { 779511f6c1aSRoger Quadros dev_err(dev, "netdev init %s failed: %d\n", 780511f6c1aSRoger Quadros eth0_node->name, ret); 781511f6c1aSRoger Quadros } 782*a99b5657SRoger Quadros goto free_pool; 783511f6c1aSRoger Quadros } 784511f6c1aSRoger Quadros } 785511f6c1aSRoger Quadros 786511f6c1aSRoger Quadros if (eth1_node) { 787511f6c1aSRoger Quadros ret = icssm_prueth_netdev_init(prueth, eth1_node); 788511f6c1aSRoger Quadros if (ret) { 789511f6c1aSRoger Quadros if (ret != -EPROBE_DEFER) { 790511f6c1aSRoger Quadros dev_err(dev, "netdev init %s failed: %d\n", 791511f6c1aSRoger Quadros eth1_node->name, ret); 792511f6c1aSRoger Quadros } 793511f6c1aSRoger Quadros goto netdev_exit; 794511f6c1aSRoger Quadros } 795511f6c1aSRoger Quadros } 796511f6c1aSRoger Quadros 797511f6c1aSRoger Quadros /* register the network devices */ 798511f6c1aSRoger Quadros if (eth0_node) { 799511f6c1aSRoger Quadros ret = register_netdev(prueth->emac[PRUETH_MAC0]->ndev); 800511f6c1aSRoger Quadros if (ret) { 801511f6c1aSRoger Quadros dev_err(dev, "can't register netdev for port MII0"); 802511f6c1aSRoger Quadros goto netdev_exit; 803511f6c1aSRoger Quadros } 804511f6c1aSRoger Quadros 805511f6c1aSRoger Quadros prueth->registered_netdevs[PRUETH_MAC0] = 806511f6c1aSRoger Quadros prueth->emac[PRUETH_MAC0]->ndev; 807511f6c1aSRoger Quadros } 808511f6c1aSRoger Quadros 809511f6c1aSRoger Quadros if (eth1_node) { 810511f6c1aSRoger Quadros ret = register_netdev(prueth->emac[PRUETH_MAC1]->ndev); 811511f6c1aSRoger Quadros if (ret) { 812511f6c1aSRoger Quadros dev_err(dev, "can't register netdev for port MII1"); 813511f6c1aSRoger Quadros goto netdev_unregister; 814511f6c1aSRoger Quadros } 815511f6c1aSRoger Quadros 816511f6c1aSRoger Quadros prueth->registered_netdevs[PRUETH_MAC1] = 817511f6c1aSRoger Quadros prueth->emac[PRUETH_MAC1]->ndev; 818511f6c1aSRoger Quadros } 819511f6c1aSRoger Quadros 820*a99b5657SRoger Quadros dev_info(dev, "TI PRU ethernet driver initialized: %s EMAC mode\n", 821*a99b5657SRoger Quadros (!eth0_node || !eth1_node) ? "single" : "dual"); 822*a99b5657SRoger Quadros 823511f6c1aSRoger Quadros if (eth1_node) 824511f6c1aSRoger Quadros of_node_put(eth1_node); 825511f6c1aSRoger Quadros if (eth0_node) 826511f6c1aSRoger Quadros of_node_put(eth0_node); 827511f6c1aSRoger Quadros return 0; 828511f6c1aSRoger Quadros 829511f6c1aSRoger Quadros netdev_unregister: 830511f6c1aSRoger Quadros for (i = 0; i < PRUETH_NUM_MACS; i++) { 831511f6c1aSRoger Quadros if (!prueth->registered_netdevs[i]) 832511f6c1aSRoger Quadros continue; 833511f6c1aSRoger Quadros unregister_netdev(prueth->registered_netdevs[i]); 834511f6c1aSRoger Quadros } 835511f6c1aSRoger Quadros 836511f6c1aSRoger Quadros netdev_exit: 837511f6c1aSRoger Quadros for (i = 0; i < PRUETH_NUM_MACS; i++) { 838511f6c1aSRoger Quadros eth_node = prueth->eth_node[i]; 839511f6c1aSRoger Quadros if (!eth_node) 840511f6c1aSRoger Quadros continue; 841511f6c1aSRoger Quadros 842511f6c1aSRoger Quadros icssm_prueth_netdev_exit(prueth, eth_node); 843511f6c1aSRoger Quadros } 844511f6c1aSRoger Quadros 845*a99b5657SRoger Quadros free_pool: 846*a99b5657SRoger Quadros gen_pool_free(prueth->sram_pool, 847*a99b5657SRoger Quadros (unsigned long)prueth->mem[PRUETH_MEM_OCMC].va, 848*a99b5657SRoger Quadros prueth->ocmc_ram_size); 849*a99b5657SRoger Quadros 850*a99b5657SRoger Quadros put_mem: 851*a99b5657SRoger Quadros for (i = PRUETH_MEM_DRAM0; i < PRUETH_MEM_OCMC; i++) { 852*a99b5657SRoger Quadros if (prueth->mem[i].va) 853*a99b5657SRoger Quadros pruss_release_mem_region(pruss, &prueth->mem[i]); 854*a99b5657SRoger Quadros } 855*a99b5657SRoger Quadros pruss_put(prueth->pruss); 856*a99b5657SRoger Quadros 857511f6c1aSRoger Quadros put_pru: 858511f6c1aSRoger Quadros if (eth1_node) { 859511f6c1aSRoger Quadros if (prueth->pru1) 860511f6c1aSRoger Quadros pru_rproc_put(prueth->pru1); 861511f6c1aSRoger Quadros of_node_put(eth1_node); 862511f6c1aSRoger Quadros } 863511f6c1aSRoger Quadros 864511f6c1aSRoger Quadros if (eth0_node) { 865511f6c1aSRoger Quadros if (prueth->pru0) 866511f6c1aSRoger Quadros pru_rproc_put(prueth->pru0); 867511f6c1aSRoger Quadros of_node_put(eth0_node); 868511f6c1aSRoger Quadros } 869511f6c1aSRoger Quadros 870511f6c1aSRoger Quadros return ret; 871511f6c1aSRoger Quadros } 872511f6c1aSRoger Quadros 873511f6c1aSRoger Quadros static void icssm_prueth_remove(struct platform_device *pdev) 874511f6c1aSRoger Quadros { 875511f6c1aSRoger Quadros struct prueth *prueth = platform_get_drvdata(pdev); 876511f6c1aSRoger Quadros struct device_node *eth_node; 877511f6c1aSRoger Quadros int i; 878511f6c1aSRoger Quadros 879511f6c1aSRoger Quadros for (i = 0; i < PRUETH_NUM_MACS; i++) { 880511f6c1aSRoger Quadros if (!prueth->registered_netdevs[i]) 881511f6c1aSRoger Quadros continue; 882511f6c1aSRoger Quadros unregister_netdev(prueth->registered_netdevs[i]); 883511f6c1aSRoger Quadros } 884511f6c1aSRoger Quadros 885511f6c1aSRoger Quadros for (i = 0; i < PRUETH_NUM_MACS; i++) { 886511f6c1aSRoger Quadros eth_node = prueth->eth_node[i]; 887511f6c1aSRoger Quadros if (!eth_node) 888511f6c1aSRoger Quadros continue; 889511f6c1aSRoger Quadros 890511f6c1aSRoger Quadros icssm_prueth_netdev_exit(prueth, eth_node); 891511f6c1aSRoger Quadros of_node_put(eth_node); 892511f6c1aSRoger Quadros } 893511f6c1aSRoger Quadros 894*a99b5657SRoger Quadros gen_pool_free(prueth->sram_pool, 895*a99b5657SRoger Quadros (unsigned long)prueth->mem[PRUETH_MEM_OCMC].va, 896*a99b5657SRoger Quadros prueth->ocmc_ram_size); 897*a99b5657SRoger Quadros 898*a99b5657SRoger Quadros for (i = PRUETH_MEM_DRAM0; i < PRUETH_MEM_OCMC; i++) { 899*a99b5657SRoger Quadros if (prueth->mem[i].va) 900*a99b5657SRoger Quadros pruss_release_mem_region(prueth->pruss, 901*a99b5657SRoger Quadros &prueth->mem[i]); 902*a99b5657SRoger Quadros } 903*a99b5657SRoger Quadros 904511f6c1aSRoger Quadros pruss_put(prueth->pruss); 905511f6c1aSRoger Quadros 906511f6c1aSRoger Quadros if (prueth->eth_node[PRUETH_MAC0]) 907511f6c1aSRoger Quadros pru_rproc_put(prueth->pru0); 908511f6c1aSRoger Quadros if (prueth->eth_node[PRUETH_MAC1]) 909511f6c1aSRoger Quadros pru_rproc_put(prueth->pru1); 910511f6c1aSRoger Quadros } 911511f6c1aSRoger Quadros 912511f6c1aSRoger Quadros #ifdef CONFIG_PM_SLEEP 913511f6c1aSRoger Quadros static int icssm_prueth_suspend(struct device *dev) 914511f6c1aSRoger Quadros { 915511f6c1aSRoger Quadros struct prueth *prueth = dev_get_drvdata(dev); 916511f6c1aSRoger Quadros struct net_device *ndev; 917511f6c1aSRoger Quadros int i, ret; 918511f6c1aSRoger Quadros 919511f6c1aSRoger Quadros for (i = 0; i < PRUETH_NUM_MACS; i++) { 920511f6c1aSRoger Quadros ndev = prueth->registered_netdevs[i]; 921511f6c1aSRoger Quadros 922511f6c1aSRoger Quadros if (!ndev) 923511f6c1aSRoger Quadros continue; 924511f6c1aSRoger Quadros 925511f6c1aSRoger Quadros if (netif_running(ndev)) { 926511f6c1aSRoger Quadros netif_device_detach(ndev); 927511f6c1aSRoger Quadros ret = icssm_emac_ndo_stop(ndev); 928511f6c1aSRoger Quadros if (ret < 0) { 929511f6c1aSRoger Quadros netdev_err(ndev, "failed to stop: %d", ret); 930511f6c1aSRoger Quadros return ret; 931511f6c1aSRoger Quadros } 932511f6c1aSRoger Quadros } 933511f6c1aSRoger Quadros } 934511f6c1aSRoger Quadros 935511f6c1aSRoger Quadros return 0; 936511f6c1aSRoger Quadros } 937511f6c1aSRoger Quadros 938511f6c1aSRoger Quadros static int icssm_prueth_resume(struct device *dev) 939511f6c1aSRoger Quadros { 940511f6c1aSRoger Quadros struct prueth *prueth = dev_get_drvdata(dev); 941511f6c1aSRoger Quadros struct net_device *ndev; 942511f6c1aSRoger Quadros int i, ret; 943511f6c1aSRoger Quadros 944511f6c1aSRoger Quadros for (i = 0; i < PRUETH_NUM_MACS; i++) { 945511f6c1aSRoger Quadros ndev = prueth->registered_netdevs[i]; 946511f6c1aSRoger Quadros 947511f6c1aSRoger Quadros if (!ndev) 948511f6c1aSRoger Quadros continue; 949511f6c1aSRoger Quadros 950511f6c1aSRoger Quadros if (netif_running(ndev)) { 951511f6c1aSRoger Quadros ret = icssm_emac_ndo_open(ndev); 952511f6c1aSRoger Quadros if (ret < 0) { 953511f6c1aSRoger Quadros netdev_err(ndev, "failed to start: %d", ret); 954511f6c1aSRoger Quadros return ret; 955511f6c1aSRoger Quadros } 956511f6c1aSRoger Quadros netif_device_attach(ndev); 957511f6c1aSRoger Quadros } 958511f6c1aSRoger Quadros } 959511f6c1aSRoger Quadros 960511f6c1aSRoger Quadros return 0; 961511f6c1aSRoger Quadros } 962511f6c1aSRoger Quadros 963511f6c1aSRoger Quadros #endif /* CONFIG_PM_SLEEP */ 964511f6c1aSRoger Quadros 965511f6c1aSRoger Quadros static const struct dev_pm_ops prueth_dev_pm_ops = { 966511f6c1aSRoger Quadros SET_SYSTEM_SLEEP_PM_OPS(icssm_prueth_suspend, icssm_prueth_resume) 967511f6c1aSRoger Quadros }; 968511f6c1aSRoger Quadros 969511f6c1aSRoger Quadros /* AM335x SoC-specific firmware data */ 970511f6c1aSRoger Quadros static struct prueth_private_data am335x_prueth_pdata = { 971*a99b5657SRoger Quadros .driver_data = PRUSS_AM33XX, 972511f6c1aSRoger Quadros .fw_pru[PRUSS_PRU0] = { 973511f6c1aSRoger Quadros .fw_name[PRUSS_ETHTYPE_EMAC] = 974511f6c1aSRoger Quadros "ti-pruss/am335x-pru0-prueth-fw.elf", 975511f6c1aSRoger Quadros }, 976511f6c1aSRoger Quadros .fw_pru[PRUSS_PRU1] = { 977511f6c1aSRoger Quadros .fw_name[PRUSS_ETHTYPE_EMAC] = 978511f6c1aSRoger Quadros "ti-pruss/am335x-pru1-prueth-fw.elf", 979511f6c1aSRoger Quadros }, 980511f6c1aSRoger Quadros }; 981511f6c1aSRoger Quadros 982511f6c1aSRoger Quadros /* AM437x SoC-specific firmware data */ 983511f6c1aSRoger Quadros static struct prueth_private_data am437x_prueth_pdata = { 984*a99b5657SRoger Quadros .driver_data = PRUSS_AM43XX, 985511f6c1aSRoger Quadros .fw_pru[PRUSS_PRU0] = { 986511f6c1aSRoger Quadros .fw_name[PRUSS_ETHTYPE_EMAC] = 987511f6c1aSRoger Quadros "ti-pruss/am437x-pru0-prueth-fw.elf", 988511f6c1aSRoger Quadros }, 989511f6c1aSRoger Quadros .fw_pru[PRUSS_PRU1] = { 990511f6c1aSRoger Quadros .fw_name[PRUSS_ETHTYPE_EMAC] = 991511f6c1aSRoger Quadros "ti-pruss/am437x-pru1-prueth-fw.elf", 992511f6c1aSRoger Quadros }, 993511f6c1aSRoger Quadros }; 994511f6c1aSRoger Quadros 995511f6c1aSRoger Quadros /* AM57xx SoC-specific firmware data */ 996511f6c1aSRoger Quadros static struct prueth_private_data am57xx_prueth_pdata = { 997*a99b5657SRoger Quadros .driver_data = PRUSS_AM57XX, 998511f6c1aSRoger Quadros .fw_pru[PRUSS_PRU0] = { 999511f6c1aSRoger Quadros .fw_name[PRUSS_ETHTYPE_EMAC] = 1000511f6c1aSRoger Quadros "ti-pruss/am57xx-pru0-prueth-fw.elf", 1001511f6c1aSRoger Quadros }, 1002511f6c1aSRoger Quadros .fw_pru[PRUSS_PRU1] = { 1003511f6c1aSRoger Quadros .fw_name[PRUSS_ETHTYPE_EMAC] = 1004511f6c1aSRoger Quadros "ti-pruss/am57xx-pru1-prueth-fw.elf", 1005511f6c1aSRoger Quadros }, 1006511f6c1aSRoger Quadros }; 1007511f6c1aSRoger Quadros 1008511f6c1aSRoger Quadros static const struct of_device_id prueth_dt_match[] = { 1009511f6c1aSRoger Quadros { .compatible = "ti,am57-prueth", .data = &am57xx_prueth_pdata, }, 1010511f6c1aSRoger Quadros { .compatible = "ti,am4376-prueth", .data = &am437x_prueth_pdata, }, 1011511f6c1aSRoger Quadros { .compatible = "ti,am3359-prueth", .data = &am335x_prueth_pdata, }, 1012511f6c1aSRoger Quadros { /* sentinel */ } 1013511f6c1aSRoger Quadros }; 1014511f6c1aSRoger Quadros MODULE_DEVICE_TABLE(of, prueth_dt_match); 1015511f6c1aSRoger Quadros 1016511f6c1aSRoger Quadros static struct platform_driver prueth_driver = { 1017511f6c1aSRoger Quadros .probe = icssm_prueth_probe, 1018511f6c1aSRoger Quadros .remove = icssm_prueth_remove, 1019511f6c1aSRoger Quadros .driver = { 1020511f6c1aSRoger Quadros .name = "prueth", 1021511f6c1aSRoger Quadros .of_match_table = prueth_dt_match, 1022511f6c1aSRoger Quadros .pm = &prueth_dev_pm_ops, 1023511f6c1aSRoger Quadros }, 1024511f6c1aSRoger Quadros }; 1025511f6c1aSRoger Quadros module_platform_driver(prueth_driver); 1026511f6c1aSRoger Quadros 1027511f6c1aSRoger Quadros MODULE_AUTHOR("Roger Quadros <rogerq@ti.com>"); 1028511f6c1aSRoger Quadros MODULE_AUTHOR("Andrew F. Davis <afd@ti.com>"); 1029511f6c1aSRoger Quadros MODULE_DESCRIPTION("PRUSS ICSSM Ethernet Driver"); 1030511f6c1aSRoger Quadros MODULE_LICENSE("GPL"); 1031