blob: 60d21537b807f0105ed97c99102b7faa26a470ff [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
7#include <common.h>
8#include <dm.h>
9#include <errno.h>
10#include <pci.h>
11#include <miiphy.h>
12#include <asm/io.h>
13#include <asm/processor.h>
14#include <miiphy.h>
15
16#include "fsl_enetc.h"
17
18static void enetc_mdio_wait_bsy(struct enetc_mdio_priv *priv)
19{
20 while (enetc_read(priv, ENETC_MDIO_CFG) & ENETC_EMDIO_CFG_BSY)
21 cpu_relax();
22}
23
Alex Marginean38882ae2019-07-03 12:11:42 +030024int enetc_mdio_read_priv(struct enetc_mdio_priv *priv, int addr, int devad,
25 int reg)
Alex Marginean02155392019-07-03 12:11:41 +030026{
27 if (devad == MDIO_DEVAD_NONE)
28 enetc_write(priv, ENETC_MDIO_CFG, ENETC_EMDIO_CFG_C22);
29 else
30 enetc_write(priv, ENETC_MDIO_CFG, ENETC_EMDIO_CFG_C45);
31 enetc_mdio_wait_bsy(priv);
32
33 if (devad == MDIO_DEVAD_NONE) {
34 enetc_write(priv, ENETC_MDIO_CTL, ENETC_MDIO_CTL_READ |
35 (addr << 5) | reg);
36 } else {
37 enetc_write(priv, ENETC_MDIO_CTL, (addr << 5) + devad);
38 enetc_mdio_wait_bsy(priv);
39
40 enetc_write(priv, ENETC_MDIO_STAT, reg);
41 enetc_mdio_wait_bsy(priv);
42
43 enetc_write(priv, ENETC_MDIO_CTL, ENETC_MDIO_CTL_READ |
44 (addr << 5) | devad);
45 }
46
47 enetc_mdio_wait_bsy(priv);
48 if (enetc_read(priv, ENETC_MDIO_CFG) & ENETC_EMDIO_CFG_RD_ER)
49 return ENETC_MDIO_READ_ERR;
50
51 return enetc_read(priv, ENETC_MDIO_DATA);
52}
53
Alex Marginean38882ae2019-07-03 12:11:42 +030054int enetc_mdio_write_priv(struct enetc_mdio_priv *priv, int addr, int devad,
55 int reg, u16 val)
Alex Marginean02155392019-07-03 12:11:41 +030056{
57 if (devad == MDIO_DEVAD_NONE)
58 enetc_write(priv, ENETC_MDIO_CFG, ENETC_EMDIO_CFG_C22);
59 else
60 enetc_write(priv, ENETC_MDIO_CFG, ENETC_EMDIO_CFG_C45);
61 enetc_mdio_wait_bsy(priv);
62
63 if (devad != MDIO_DEVAD_NONE) {
64 enetc_write(priv, ENETC_MDIO_CTL, (addr << 5) + devad);
65 enetc_write(priv, ENETC_MDIO_STAT, reg);
66 } else {
67 enetc_write(priv, ENETC_MDIO_CTL, (addr << 5) + reg);
68 }
69 enetc_mdio_wait_bsy(priv);
70
71 enetc_write(priv, ENETC_MDIO_DATA, val);
72 enetc_mdio_wait_bsy(priv);
73
74 return 0;
75}
76
77/* DM wrappers */
78static int dm_enetc_mdio_read(struct udevice *dev, int addr, int devad, int reg)
79{
80 struct enetc_mdio_priv *priv = dev_get_priv(dev);
81
82 return enetc_mdio_read_priv(priv, addr, devad, reg);
83}
84
85static int dm_enetc_mdio_write(struct udevice *dev, int addr, int devad,
86 int reg, u16 val)
87{
88 struct enetc_mdio_priv *priv = dev_get_priv(dev);
89
90 return enetc_mdio_write_priv(priv, addr, devad, reg, val);
91}
92
93static const struct mdio_ops enetc_mdio_ops = {
94 .read = dm_enetc_mdio_read,
95 .write = dm_enetc_mdio_write,
96};
97
98static int enetc_mdio_bind(struct udevice *dev)
99{
100 char name[16];
101 static int eth_num_devices;
102
103 /*
104 * prefer using PCI function numbers to number interfaces, but these
105 * are only available if dts nodes are present. For PCI they are
106 * optional, handle that case too. Just in case some nodes are present
107 * and some are not, use different naming scheme - enetc-N based on
108 * PCI function # and enetc#N based on interface count
109 */
110 if (ofnode_valid(dev->node))
111 sprintf(name, "emdio-%u", PCI_FUNC(pci_get_devfn(dev)));
112 else
113 sprintf(name, "emdio#%u", eth_num_devices++);
114 device_set_name(dev, name);
115
116 return 0;
117}
118
119static int enetc_mdio_probe(struct udevice *dev)
120{
121 struct enetc_mdio_priv *priv = dev_get_priv(dev);
122
123 priv->regs_base = dm_pci_map_bar(dev, PCI_BASE_ADDRESS_0, 0);
124 if (!priv->regs_base) {
125 enetc_dbg(dev, "failed to map BAR0\n");
126 return -EINVAL;
127 }
128
129 priv->regs_base += ENETC_MDIO_BASE;
130
131 dm_pci_clrset_config16(dev, PCI_COMMAND, 0, PCI_COMMAND_MEMORY);
132
133 return 0;
134}
135
136U_BOOT_DRIVER(enetc_mdio) = {
137 .name = "enetc_mdio",
138 .id = UCLASS_MDIO,
139 .bind = enetc_mdio_bind,
140 .probe = enetc_mdio_probe,
141 .ops = &enetc_mdio_ops,
142 .priv_auto_alloc_size = sizeof(struct enetc_mdio_priv),
143};
144
145static struct pci_device_id enetc_mdio_ids[] = {
146 { PCI_DEVICE(PCI_VENDOR_ID_FREESCALE, PCI_DEVICE_ID_ENETC_MDIO) },
147};
148
149U_BOOT_PCI_DEVICE(enetc_mdio, enetc_mdio_ids);