raw/ifpga/base: add eth group driver
[dpdk.git] / drivers / raw / ifpga_rawdev / base / opae_eth_group.c
1 /* SPDX-License-Identifier: BSD-3-Clause
2  * Copyright(c) 2010-2019 Intel Corporation
3  */
4
5 #include "opae_osdep.h"
6 #include "opae_eth_group.h"
7
8 #define DATA_VAL_INVL           1 /* us */
9 #define DATA_VAL_POLL_TIMEOUT   10 /* us */
10
11 static const char *eth_type_to_string(u8 type)
12 {
13         switch (type) {
14         case ETH_GROUP_PHY:
15                 return "phy";
16         case ETH_GROUP_MAC:
17                 return "mac";
18         case ETH_GROUP_ETHER:
19                 return "ethernet wrapper";
20         }
21
22         return "unknown";
23 }
24
25 static int eth_group_get_select(struct eth_group_device *dev,
26                 u8 type, u8 index, u8 *select)
27 {
28         /*
29          * in different speed configuration, the index of
30          * PHY and MAC are different.
31          *
32          * 1 ethernet wrapper -> Device Select 0x0 - fixed value
33          * n PHYs             -> Device Select 0x2,4,6,8,A,C,E,10,...
34          * n MACs             -> Device Select 0x3,5,7,9,B,D,F,11,...
35          */
36
37         if (type == ETH_GROUP_PHY && index < dev->phy_num)
38                 *select = index * 2 + 2;
39         else if (type == ETH_GROUP_MAC && index < dev->mac_num)
40                 *select = index * 2 + 3;
41         else if (type == ETH_GROUP_ETHER && index == 0)
42                 *select = 0;
43         else
44                 return -EINVAL;
45
46         return 0;
47 }
48
49 int eth_group_write_reg(struct eth_group_device *dev,
50                 u8 type, u8 index, u16 addr, u32 data)
51 {
52         u8 dev_select = 0;
53         u64 v = 0;
54         int ret;
55
56         dev_debug(dev, "%s type %s index %u addr 0x%x\n",
57                         __func__, eth_type_to_string(type), index, addr);
58
59         /* find device select */
60         ret = eth_group_get_select(dev, type, index, &dev_select);
61         if (ret)
62                 return ret;
63
64         v = CMD_WR << CTRL_CMD_SHIT |
65                 (u64)dev_select << CTRL_DS_SHIFT |
66                 (u64)addr << CTRL_ADDR_SHIFT |
67                 (data & CTRL_WR_DATA);
68
69         /* only PHY has additional feature bit */
70         if (type == ETH_GROUP_PHY)
71                 v |= CTRL_FEAT_SELECT;
72
73         opae_writeq(v, dev->base + ETH_GROUP_CTRL);
74
75         return 0;
76 }
77
78 int eth_group_read_reg(struct eth_group_device *dev,
79                 u8 type, u8 index, u16 addr, u32 *data)
80 {
81         u8 dev_select = 0;
82         u64 v = 0;
83         int ret;
84
85         dev_debug(dev, "%s type %s index %u addr 0x%x\n",
86                         __func__, eth_type_to_string(type), index,
87                         addr);
88
89         /* find device select */
90         ret = eth_group_get_select(dev, type, index, &dev_select);
91         if (ret)
92                 return ret;
93
94         v = CMD_RD << CTRL_CMD_SHIT |
95                 (u64)dev_select << CTRL_DS_SHIFT |
96                 (u64)addr << CTRL_ADDR_SHIFT;
97
98         /* only PHY has additional feature bit */
99         if (type == ETH_GROUP_PHY)
100                 v |= CTRL_FEAT_SELECT;
101
102         opae_writeq(v, dev->base + ETH_GROUP_CTRL);
103
104         if (opae_readq_poll_timeout(dev->base + ETH_GROUP_STAT,
105                         v, v & STAT_DATA_VAL, DATA_VAL_INVL,
106                         DATA_VAL_POLL_TIMEOUT))
107                 return -ETIMEDOUT;
108
109         *data = (v & STAT_RD_DATA);
110
111         dev_debug(dev, "%s data 0x%x\n", __func__, *data);
112
113         return 0;
114 }
115
116 struct eth_group_device *eth_group_probe(void *base)
117 {
118         struct eth_group_device *dev;
119
120         dev = opae_malloc(sizeof(*dev));
121         if (!dev)
122                 return NULL;
123
124         dev->base = (u8 *)base;
125
126         dev->info.info = opae_readq(dev->base + ETH_GROUP_INFO);
127         dev->group_id = dev->info.group_id;
128         dev->phy_num = dev->mac_num = dev->info.num_phys;
129         dev->speed = dev->info.speed;
130
131         dev->status = ETH_GROUP_DEV_ATTACHED;
132
133         dev_info(dev, "eth group device %d probe done: phy_num=mac_num:%d, speed=%d\n",
134                         dev->group_id, dev->phy_num, dev->speed);
135
136         return dev;
137 }
138
139 void eth_group_release(struct eth_group_device *dev)
140 {
141         if (dev) {
142                 dev->status = ETH_GROUP_DEV_NOUSED;
143                 opae_free(dev);
144         }
145 }