blob: 2d5fcbb6dbd3a610c6cbb49dd8b87cb14cbe52b2 [file] [log] [blame]
Alex Marginean02155392019-07-03 12:11:41 +03001// SPDX-License-Identifier: GPL-2.0+
2/*
3 * ENETC ethernet controller driver
4 * Copyright 2019 NXP
5 */
6
Alex Marginean02155392019-07-03 12:11:41 +03007#include <dm.h>
8#include <errno.h>
9#include <pci.h>
10#include <miiphy.h>
11#include <asm/io.h>
12#include <asm/processor.h>
13#include <miiphy.h>
14
15#include "fsl_enetc.h"
16
17static void enetc_mdio_wait_bsy(struct enetc_mdio_priv *priv)
18{
Alex Marginean05b48772019-11-14 18:58:47 +020019 int to = 10000;
20
21 while ((enetc_read(priv, ENETC_MDIO_CFG) & ENETC_EMDIO_CFG_BSY) &&
22 --to)
Alex Marginean02155392019-07-03 12:11:41 +030023 cpu_relax();
Alex Marginean05b48772019-11-14 18:58:47 +020024 if (!to)
25 printf("T");
Alex Marginean02155392019-07-03 12:11:41 +030026}
27
Alex Marginean38882ae2019-07-03 12:11:42 +030028int enetc_mdio_read_priv(struct enetc_mdio_priv *priv, int addr, int devad,
29 int reg)
Alex Marginean02155392019-07-03 12:11:41 +030030{
31 if (devad == MDIO_DEVAD_NONE)
32 enetc_write(priv, ENETC_MDIO_CFG, ENETC_EMDIO_CFG_C22);
33 else
34 enetc_write(priv, ENETC_MDIO_CFG, ENETC_EMDIO_CFG_C45);
35 enetc_mdio_wait_bsy(priv);
36
37 if (devad == MDIO_DEVAD_NONE) {
38 enetc_write(priv, ENETC_MDIO_CTL, ENETC_MDIO_CTL_READ |
39 (addr << 5) | reg);
40 } else {
41 enetc_write(priv, ENETC_MDIO_CTL, (addr << 5) + devad);
42 enetc_mdio_wait_bsy(priv);
43
44 enetc_write(priv, ENETC_MDIO_STAT, reg);
45 enetc_mdio_wait_bsy(priv);
46
47 enetc_write(priv, ENETC_MDIO_CTL, ENETC_MDIO_CTL_READ |
48 (addr << 5) | devad);
49 }
50
51 enetc_mdio_wait_bsy(priv);
52 if (enetc_read(priv, ENETC_MDIO_CFG) & ENETC_EMDIO_CFG_RD_ER)
53 return ENETC_MDIO_READ_ERR;
54
55 return enetc_read(priv, ENETC_MDIO_DATA);
56}
57
Alex Marginean38882ae2019-07-03 12:11:42 +030058int enetc_mdio_write_priv(struct enetc_mdio_priv *priv, int addr, int devad,
59 int reg, u16 val)
Alex Marginean02155392019-07-03 12:11:41 +030060{
61 if (devad == MDIO_DEVAD_NONE)
62 enetc_write(priv, ENETC_MDIO_CFG, ENETC_EMDIO_CFG_C22);
63 else
64 enetc_write(priv, ENETC_MDIO_CFG, ENETC_EMDIO_CFG_C45);
65 enetc_mdio_wait_bsy(priv);
66
67 if (devad != MDIO_DEVAD_NONE) {
68 enetc_write(priv, ENETC_MDIO_CTL, (addr << 5) + devad);
69 enetc_write(priv, ENETC_MDIO_STAT, reg);
70 } else {
71 enetc_write(priv, ENETC_MDIO_CTL, (addr << 5) + reg);
72 }
73 enetc_mdio_wait_bsy(priv);
74
75 enetc_write(priv, ENETC_MDIO_DATA, val);
76 enetc_mdio_wait_bsy(priv);
77
78 return 0;
79}
80
81/* DM wrappers */
82static int dm_enetc_mdio_read(struct udevice *dev, int addr, int devad, int reg)
83{
84 struct enetc_mdio_priv *priv = dev_get_priv(dev);
85
86 return enetc_mdio_read_priv(priv, addr, devad, reg);
87}
88
89static int dm_enetc_mdio_write(struct udevice *dev, int addr, int devad,
90 int reg, u16 val)
91{
92 struct enetc_mdio_priv *priv = dev_get_priv(dev);
93
94 return enetc_mdio_write_priv(priv, addr, devad, reg, val);
95}
96
97static const struct mdio_ops enetc_mdio_ops = {
98 .read = dm_enetc_mdio_read,
99 .write = dm_enetc_mdio_write,
100};
101
102static int enetc_mdio_bind(struct udevice *dev)
103{
104 char name[16];
105 static int eth_num_devices;
106
107 /*
108 * prefer using PCI function numbers to number interfaces, but these
109 * are only available if dts nodes are present. For PCI they are
110 * optional, handle that case too. Just in case some nodes are present
111 * and some are not, use different naming scheme - enetc-N based on
112 * PCI function # and enetc#N based on interface count
113 */
Simon Glassa7ece582020-12-19 10:40:14 -0700114 if (ofnode_valid(dev_ofnode(dev)))
Alex Marginean02155392019-07-03 12:11:41 +0300115 sprintf(name, "emdio-%u", PCI_FUNC(pci_get_devfn(dev)));
116 else
117 sprintf(name, "emdio#%u", eth_num_devices++);
118 device_set_name(dev, name);
119
120 return 0;
121}
122
123static int enetc_mdio_probe(struct udevice *dev)
124{
125 struct enetc_mdio_priv *priv = dev_get_priv(dev);
126
Andrew Scull6520c822022-04-21 16:11:13 +0000127 priv->regs_base = dm_pci_map_bar(dev, PCI_BASE_ADDRESS_0, 0, 0, PCI_REGION_TYPE, 0);
Alex Marginean02155392019-07-03 12:11:41 +0300128 if (!priv->regs_base) {
129 enetc_dbg(dev, "failed to map BAR0\n");
130 return -EINVAL;
131 }
132
133 priv->regs_base += ENETC_MDIO_BASE;
134
135 dm_pci_clrset_config16(dev, PCI_COMMAND, 0, PCI_COMMAND_MEMORY);
136
137 return 0;
138}
139
140U_BOOT_DRIVER(enetc_mdio) = {
141 .name = "enetc_mdio",
142 .id = UCLASS_MDIO,
143 .bind = enetc_mdio_bind,
144 .probe = enetc_mdio_probe,
145 .ops = &enetc_mdio_ops,
Simon Glass8a2b47f2020-12-03 16:55:17 -0700146 .priv_auto = sizeof(struct enetc_mdio_priv),
Alex Marginean02155392019-07-03 12:11:41 +0300147};
148
149static struct pci_device_id enetc_mdio_ids[] = {
150 { PCI_DEVICE(PCI_VENDOR_ID_FREESCALE, PCI_DEVICE_ID_ENETC_MDIO) },
Alex Marginean881bcb62019-08-07 19:33:22 +0300151 { }
Alex Marginean02155392019-07-03 12:11:41 +0300152};
153
154U_BOOT_PCI_DEVICE(enetc_mdio, enetc_mdio_ids);