blob: 3eb6ac9fc8f036c40dcad7a70d36873017a63b0e [file] [log] [blame]
Alex Marginean1d995342019-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{
Alex Marginean6c964462019-11-14 18:58:47 +020020 int to = 10000;
21
22 while ((enetc_read(priv, ENETC_MDIO_CFG) & ENETC_EMDIO_CFG_BSY) &&
23 --to)
Alex Marginean1d995342019-07-03 12:11:41 +030024 cpu_relax();
Alex Marginean6c964462019-11-14 18:58:47 +020025 if (!to)
26 printf("T");
Alex Marginean1d995342019-07-03 12:11:41 +030027}
28
Alex Margineane4aafd52019-07-03 12:11:42 +030029int enetc_mdio_read_priv(struct enetc_mdio_priv *priv, int addr, int devad,
30 int reg)
Alex Marginean1d995342019-07-03 12:11:41 +030031{
32 if (devad == MDIO_DEVAD_NONE)
33 enetc_write(priv, ENETC_MDIO_CFG, ENETC_EMDIO_CFG_C22);
34 else
35 enetc_write(priv, ENETC_MDIO_CFG, ENETC_EMDIO_CFG_C45);
36 enetc_mdio_wait_bsy(priv);
37
38 if (devad == MDIO_DEVAD_NONE) {
39 enetc_write(priv, ENETC_MDIO_CTL, ENETC_MDIO_CTL_READ |
40 (addr << 5) | reg);
41 } else {
42 enetc_write(priv, ENETC_MDIO_CTL, (addr << 5) + devad);
43 enetc_mdio_wait_bsy(priv);
44
45 enetc_write(priv, ENETC_MDIO_STAT, reg);
46 enetc_mdio_wait_bsy(priv);
47
48 enetc_write(priv, ENETC_MDIO_CTL, ENETC_MDIO_CTL_READ |
49 (addr << 5) | devad);
50 }
51
52 enetc_mdio_wait_bsy(priv);
53 if (enetc_read(priv, ENETC_MDIO_CFG) & ENETC_EMDIO_CFG_RD_ER)
54 return ENETC_MDIO_READ_ERR;
55
56 return enetc_read(priv, ENETC_MDIO_DATA);
57}
58
Alex Margineane4aafd52019-07-03 12:11:42 +030059int enetc_mdio_write_priv(struct enetc_mdio_priv *priv, int addr, int devad,
60 int reg, u16 val)
Alex Marginean1d995342019-07-03 12:11:41 +030061{
62 if (devad == MDIO_DEVAD_NONE)
63 enetc_write(priv, ENETC_MDIO_CFG, ENETC_EMDIO_CFG_C22);
64 else
65 enetc_write(priv, ENETC_MDIO_CFG, ENETC_EMDIO_CFG_C45);
66 enetc_mdio_wait_bsy(priv);
67
68 if (devad != MDIO_DEVAD_NONE) {
69 enetc_write(priv, ENETC_MDIO_CTL, (addr << 5) + devad);
70 enetc_write(priv, ENETC_MDIO_STAT, reg);
71 } else {
72 enetc_write(priv, ENETC_MDIO_CTL, (addr << 5) + reg);
73 }
74 enetc_mdio_wait_bsy(priv);
75
76 enetc_write(priv, ENETC_MDIO_DATA, val);
77 enetc_mdio_wait_bsy(priv);
78
79 return 0;
80}
81
82/* DM wrappers */
83static int dm_enetc_mdio_read(struct udevice *dev, int addr, int devad, int reg)
84{
85 struct enetc_mdio_priv *priv = dev_get_priv(dev);
86
87 return enetc_mdio_read_priv(priv, addr, devad, reg);
88}
89
90static int dm_enetc_mdio_write(struct udevice *dev, int addr, int devad,
91 int reg, u16 val)
92{
93 struct enetc_mdio_priv *priv = dev_get_priv(dev);
94
95 return enetc_mdio_write_priv(priv, addr, devad, reg, val);
96}
97
98static const struct mdio_ops enetc_mdio_ops = {
99 .read = dm_enetc_mdio_read,
100 .write = dm_enetc_mdio_write,
101};
102
103static int enetc_mdio_bind(struct udevice *dev)
104{
105 char name[16];
106 static int eth_num_devices;
107
108 /*
109 * prefer using PCI function numbers to number interfaces, but these
110 * are only available if dts nodes are present. For PCI they are
111 * optional, handle that case too. Just in case some nodes are present
112 * and some are not, use different naming scheme - enetc-N based on
113 * PCI function # and enetc#N based on interface count
114 */
Simon Glassf10643c2020-12-19 10:40:14 -0700115 if (ofnode_valid(dev_ofnode(dev)))
Alex Marginean1d995342019-07-03 12:11:41 +0300116 sprintf(name, "emdio-%u", PCI_FUNC(pci_get_devfn(dev)));
117 else
118 sprintf(name, "emdio#%u", eth_num_devices++);
119 device_set_name(dev, name);
120
121 return 0;
122}
123
124static int enetc_mdio_probe(struct udevice *dev)
125{
126 struct enetc_mdio_priv *priv = dev_get_priv(dev);
127
128 priv->regs_base = dm_pci_map_bar(dev, PCI_BASE_ADDRESS_0, 0);
129 if (!priv->regs_base) {
130 enetc_dbg(dev, "failed to map BAR0\n");
131 return -EINVAL;
132 }
133
134 priv->regs_base += ENETC_MDIO_BASE;
135
136 dm_pci_clrset_config16(dev, PCI_COMMAND, 0, PCI_COMMAND_MEMORY);
137
138 return 0;
139}
140
141U_BOOT_DRIVER(enetc_mdio) = {
142 .name = "enetc_mdio",
143 .id = UCLASS_MDIO,
144 .bind = enetc_mdio_bind,
145 .probe = enetc_mdio_probe,
146 .ops = &enetc_mdio_ops,
Simon Glass41575d82020-12-03 16:55:17 -0700147 .priv_auto = sizeof(struct enetc_mdio_priv),
Alex Marginean1d995342019-07-03 12:11:41 +0300148};
149
150static struct pci_device_id enetc_mdio_ids[] = {
151 { PCI_DEVICE(PCI_VENDOR_ID_FREESCALE, PCI_DEVICE_ID_ENETC_MDIO) },
Alex Margineane3562b32019-08-07 19:33:22 +0300152 { }
Alex Marginean1d995342019-07-03 12:11:41 +0300153};
154
155U_BOOT_PCI_DEVICE(enetc_mdio, enetc_mdio_ids);