]> Git Repo - J-u-boot.git/blob - drivers/net/octeontx/smi.c
common: Drop asm/global_data.h from common header
[J-u-boot.git] / drivers / net / octeontx / smi.c
1 // SPDX-License-Identifier:    GPL-2.0
2 /*
3  * Copyright (C) 2018 Marvell International Ltd.
4  */
5
6 #include <dm.h>
7 #include <malloc.h>
8 #include <miiphy.h>
9 #include <misc.h>
10 #include <pci.h>
11 #include <pci_ids.h>
12 #include <phy.h>
13 #include <asm/global_data.h>
14 #include <asm/io.h>
15 #include <linux/ctype.h>
16 #include <linux/delay.h>
17
18 #define PCI_DEVICE_ID_OCTEONTX_SMI 0xA02B
19
20 DECLARE_GLOBAL_DATA_PTR;
21
22 enum octeontx_smi_mode {
23         CLAUSE22 = 0,
24         CLAUSE45 = 1,
25 };
26
27 enum {
28         SMI_OP_C22_WRITE = 0,
29         SMI_OP_C22_READ = 1,
30
31         SMI_OP_C45_ADDR = 0,
32         SMI_OP_C45_WRITE = 1,
33         SMI_OP_C45_PRIA = 2,
34         SMI_OP_C45_READ = 3,
35 };
36
37 union smi_x_clk {
38         u64 u;
39         struct smi_x_clk_s {
40                 int phase:8;
41                 int sample:4;
42                 int preamble:1;
43                 int clk_idle:1;
44                 int reserved_14_14:1;
45                 int sample_mode:1;
46                 int sample_hi:5;
47                 int reserved_21_23:3;
48                 int mode:1;
49         } s;
50 };
51
52 union smi_x_cmd {
53         u64 u;
54         struct smi_x_cmd_s {
55                 int reg_adr:5;
56                 int reserved_5_7:3;
57                 int phy_adr:5;
58                 int reserved_13_15:3;
59                 int phy_op:2;
60         } s;
61 };
62
63 union smi_x_wr_dat {
64         u64 u;
65         struct smi_x_wr_dat_s {
66                 unsigned int dat:16;
67                 int val:1;
68                 int pending:1;
69         } s;
70 };
71
72 union smi_x_rd_dat {
73         u64 u;
74         struct smi_x_rd_dat_s {
75                 unsigned int dat:16;
76                 int val:1;
77                 int pending:1;
78         } s;
79 };
80
81 union smi_x_en {
82         u64 u;
83         struct smi_x_en_s {
84                 int en:1;
85         } s;
86 };
87
88 #define SMI_X_RD_DAT    0x10ull
89 #define SMI_X_WR_DAT    0x08ull
90 #define SMI_X_CMD       0x00ull
91 #define SMI_X_CLK       0x18ull
92 #define SMI_X_EN        0x20ull
93
94 struct octeontx_smi_priv {
95         void __iomem *baseaddr;
96         enum octeontx_smi_mode mode;
97 };
98
99 #define MDIO_TIMEOUT 10000
100
101 void octeontx_smi_setmode(struct mii_dev *bus, enum octeontx_smi_mode mode)
102 {
103         struct octeontx_smi_priv *priv = bus->priv;
104         union smi_x_clk smix_clk;
105
106         smix_clk.u = readq(priv->baseaddr + SMI_X_CLK);
107         smix_clk.s.mode = mode;
108         smix_clk.s.preamble = mode == CLAUSE45;
109         writeq(smix_clk.u, priv->baseaddr + SMI_X_CLK);
110
111         priv->mode = mode;
112 }
113
114 int octeontx_c45_addr(struct mii_dev *bus, int addr, int devad, int regnum)
115 {
116         struct octeontx_smi_priv *priv = bus->priv;
117
118         union smi_x_cmd smix_cmd;
119         union smi_x_wr_dat smix_wr_dat;
120         unsigned long timeout = MDIO_TIMEOUT;
121
122         smix_wr_dat.u = 0;
123         smix_wr_dat.s.dat = regnum;
124
125         writeq(smix_wr_dat.u, priv->baseaddr + SMI_X_WR_DAT);
126
127         smix_cmd.u = 0;
128         smix_cmd.s.phy_op = SMI_OP_C45_ADDR;
129         smix_cmd.s.phy_adr = addr;
130         smix_cmd.s.reg_adr = devad;
131
132         writeq(smix_cmd.u, priv->baseaddr + SMI_X_CMD);
133
134         do {
135                 smix_wr_dat.u = readq(priv->baseaddr + SMI_X_WR_DAT);
136                 udelay(100);
137                 timeout--;
138         } while (smix_wr_dat.s.pending && timeout);
139
140         return timeout == 0;
141 }
142
143 int octeontx_phy_read(struct mii_dev *bus, int addr, int devad, int regnum)
144 {
145         struct octeontx_smi_priv *priv = bus->priv;
146         union smi_x_cmd smix_cmd;
147         union smi_x_rd_dat smix_rd_dat;
148         unsigned long timeout = MDIO_TIMEOUT;
149         int ret;
150
151         enum octeontx_smi_mode mode = (devad < 0) ? CLAUSE22 : CLAUSE45;
152
153         debug("RD: Mode: %u, baseaddr: %p, addr: %d, devad: %d, reg: %d\n",
154               mode, priv->baseaddr, addr, devad, regnum);
155
156         octeontx_smi_setmode(bus, mode);
157
158         if (mode == CLAUSE45) {
159                 ret = octeontx_c45_addr(bus, addr, devad, regnum);
160
161                 debug("RD: ret: %u\n", ret);
162
163                 if (ret)
164                         return 0;
165         }
166
167         smix_cmd.u = 0;
168         smix_cmd.s.phy_adr = addr;
169
170         if (mode == CLAUSE45) {
171                 smix_cmd.s.reg_adr = devad;
172                 smix_cmd.s.phy_op = SMI_OP_C45_READ;
173         } else {
174                 smix_cmd.s.reg_adr = regnum;
175                 smix_cmd.s.phy_op = SMI_OP_C22_READ;
176         }
177
178         writeq(smix_cmd.u, priv->baseaddr + SMI_X_CMD);
179
180         do {
181                 smix_rd_dat.u = readq(priv->baseaddr + SMI_X_RD_DAT);
182                 udelay(10);
183                 timeout--;
184         } while (smix_rd_dat.s.pending && timeout);
185
186         debug("SMIX_RD_DAT: %lx\n", (unsigned long)smix_rd_dat.u);
187
188         return smix_rd_dat.s.dat;
189 }
190
191 int octeontx_phy_write(struct mii_dev *bus, int addr, int devad, int regnum,
192                        u16 value)
193 {
194         struct octeontx_smi_priv *priv = bus->priv;
195         union smi_x_cmd smix_cmd;
196         union smi_x_wr_dat smix_wr_dat;
197         unsigned long timeout = MDIO_TIMEOUT;
198         int ret;
199
200         enum octeontx_smi_mode mode = (devad < 0) ? CLAUSE22 : CLAUSE45;
201
202         debug("WR: Mode: %u, baseaddr: %p, addr: %d, devad: %d, reg: %d\n",
203               mode, priv->baseaddr, addr, devad, regnum);
204
205         if (mode == CLAUSE45) {
206                 ret = octeontx_c45_addr(bus, addr, devad, regnum);
207
208                 debug("WR: ret: %u\n", ret);
209
210                 if (ret)
211                         return ret;
212         }
213
214         smix_wr_dat.u = 0;
215         smix_wr_dat.s.dat = value;
216
217         writeq(smix_wr_dat.u, priv->baseaddr + SMI_X_WR_DAT);
218
219         smix_cmd.u = 0;
220         smix_cmd.s.phy_adr = addr;
221
222         if (mode == CLAUSE45) {
223                 smix_cmd.s.reg_adr = devad;
224                 smix_cmd.s.phy_op = SMI_OP_C45_WRITE;
225         } else {
226                 smix_cmd.s.reg_adr = regnum;
227                 smix_cmd.s.phy_op = SMI_OP_C22_WRITE;
228         }
229
230         writeq(smix_cmd.u, priv->baseaddr + SMI_X_CMD);
231
232         do {
233                 smix_wr_dat.u = readq(priv->baseaddr + SMI_X_WR_DAT);
234                 udelay(10);
235                 timeout--;
236         } while (smix_wr_dat.s.pending && timeout);
237
238         debug("SMIX_WR_DAT: %lx\n", (unsigned long)smix_wr_dat.u);
239
240         return timeout == 0;
241 }
242
243 int octeontx_smi_reset(struct mii_dev *bus)
244 {
245         struct octeontx_smi_priv *priv = bus->priv;
246
247         union smi_x_en smi_en;
248
249         smi_en.s.en = 0;
250         writeq(smi_en.u, priv->baseaddr + SMI_X_EN);
251
252         smi_en.s.en = 1;
253         writeq(smi_en.u, priv->baseaddr + SMI_X_EN);
254
255         octeontx_smi_setmode(bus, CLAUSE22);
256
257         return 0;
258 }
259
260 /* PHY XS initialization, primarily for RXAUI
261  *
262  */
263 int rxaui_phy_xs_init(struct mii_dev *bus, int phy_addr)
264 {
265         int reg;
266         ulong start_time;
267         int phy_id1, phy_id2;
268         int oui, model_number;
269
270         phy_id1 = octeontx_phy_read(bus, phy_addr, 1, 0x2);
271         phy_id2 = octeontx_phy_read(bus, phy_addr, 1, 0x3);
272         model_number = (phy_id2 >> 4) & 0x3F;
273         debug("%s model %x\n", __func__, model_number);
274         oui = phy_id1;
275         oui <<= 6;
276         oui |= (phy_id2 >> 10) & 0x3F;
277         debug("%s oui %x\n", __func__, oui);
278         switch (oui) {
279         case 0x5016:
280                 if (model_number == 9) {
281                         debug("%s +\n", __func__);
282                         /* Perform hardware reset in XGXS control */
283                         reg = octeontx_phy_read(bus, phy_addr, 4, 0x0);
284                         if ((reg & 0xffff) < 0)
285                                 goto read_error;
286                         reg |= 0x8000;
287                         octeontx_phy_write(bus, phy_addr, 4, 0x0, reg);
288
289                         start_time = get_timer(0);
290                         do {
291                                 reg = octeontx_phy_read(bus, phy_addr, 4, 0x0);
292                                 if ((reg & 0xffff) < 0)
293                                         goto read_error;
294                         } while ((reg & 0x8000) && get_timer(start_time) < 500);
295                         if (reg & 0x8000) {
296                                 printf("HW reset for M88X3120 PHY failed");
297                                 printf("MII_BMCR: 0x%x\n", reg);
298                                 return -1;
299                         }
300                         /* program 4.49155 with 0x5 */
301                         octeontx_phy_write(bus, phy_addr, 4, 0xc003, 0x5);
302                 }
303                 break;
304         default:
305                 break;
306         }
307
308         return 0;
309
310 read_error:
311         debug("M88X3120 PHY config read failed\n");
312         return -1;
313 }
314
315 int octeontx_smi_probe(struct udevice *dev)
316 {
317         int ret, subnode, cnt = 0, node = dev_ofnode(dev).of_offset;
318         struct mii_dev *bus;
319         struct octeontx_smi_priv *priv;
320         pci_dev_t bdf = dm_pci_get_bdf(dev);
321
322         debug("SMI PCI device: %x\n", bdf);
323         if (!dm_pci_map_bar(dev, PCI_BASE_ADDRESS_0, PCI_REGION_MEM)) {
324                 printf("Failed to map PCI region for bdf %x\n", bdf);
325                 return -1;
326         }
327
328         fdt_for_each_subnode(subnode, gd->fdt_blob, node) {
329                 ret = fdt_node_check_compatible(gd->fdt_blob, subnode,
330                                                 "cavium,thunder-8890-mdio");
331                 if (ret)
332                         continue;
333
334                 bus = mdio_alloc();
335                 priv = malloc(sizeof(*priv));
336                 if (!bus || !priv) {
337                         printf("Failed to allocate OcteonTX MDIO bus # %u\n",
338                                dev_seq(dev));
339                         return -1;
340                 }
341
342                 bus->read = octeontx_phy_read;
343                 bus->write = octeontx_phy_write;
344                 bus->reset = octeontx_smi_reset;
345                 bus->priv = priv;
346
347                 priv->mode = CLAUSE22;
348                 priv->baseaddr = (void __iomem *)fdtdec_get_addr(gd->fdt_blob,
349                                                                  subnode,
350                                                                  "reg");
351                 debug("mdio base addr %p\n", priv->baseaddr);
352
353                 /* use given name or generate its own unique name */
354                 snprintf(bus->name, MDIO_NAME_LEN, "smi%d", cnt++);
355
356                 ret = mdio_register(bus);
357                 if (ret)
358                         return ret;
359         }
360         return 0;
361 }
362
363 static const struct udevice_id octeontx_smi_ids[] = {
364         { .compatible = "cavium,thunder-8890-mdio-nexus" },
365         {}
366 };
367
368 U_BOOT_DRIVER(octeontx_smi) = {
369         .name   = "octeontx_smi",
370         .id     = UCLASS_MISC,
371         .probe  = octeontx_smi_probe,
372         .of_match = octeontx_smi_ids,
373 };
374
375 static struct pci_device_id octeontx_smi_supported[] = {
376         { PCI_VDEVICE(CAVIUM, PCI_DEVICE_ID_CAVIUM_SMI) },
377         {}
378 };
379
380 U_BOOT_PCI_DEVICE(octeontx_smi, octeontx_smi_supported);
This page took 0.047274 seconds and 4 git commands to generate.