blob: c1d491f2c5a78287bfb2e9a537b9cd9186d30058 [file] [log] [blame]
Alex Marginean02155392019-07-03 12:11:41 +03001// SPDX-License-Identifier: GPL-2.0+
2/*
3 * ENETC ethernet controller driver
Alice Guo9a347952025-01-16 05:03:29 +01004 * Copyright 2019-2025 NXP
Alex Marginean02155392019-07-03 12:11:41 +03005 */
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
Marek Vasutcd684142025-01-16 05:03:24 +010017static u32 enetc_read(struct enetc_mdio_priv *priv, u32 off)
18{
19 return readl(priv->regs_base + off);
20}
21
22static void enetc_write(struct enetc_mdio_priv *priv, u32 off, u32 val)
23{
24 writel(val, priv->regs_base + off);
25}
26
Alex Marginean02155392019-07-03 12:11:41 +030027static void enetc_mdio_wait_bsy(struct enetc_mdio_priv *priv)
28{
Alex Marginean05b48772019-11-14 18:58:47 +020029 int to = 10000;
30
31 while ((enetc_read(priv, ENETC_MDIO_CFG) & ENETC_EMDIO_CFG_BSY) &&
32 --to)
Alex Marginean02155392019-07-03 12:11:41 +030033 cpu_relax();
Alex Marginean05b48772019-11-14 18:58:47 +020034 if (!to)
35 printf("T");
Alex Marginean02155392019-07-03 12:11:41 +030036}
37
Alex Marginean38882ae2019-07-03 12:11:42 +030038int enetc_mdio_read_priv(struct enetc_mdio_priv *priv, int addr, int devad,
39 int reg)
Alex Marginean02155392019-07-03 12:11:41 +030040{
41 if (devad == MDIO_DEVAD_NONE)
42 enetc_write(priv, ENETC_MDIO_CFG, ENETC_EMDIO_CFG_C22);
43 else
44 enetc_write(priv, ENETC_MDIO_CFG, ENETC_EMDIO_CFG_C45);
45 enetc_mdio_wait_bsy(priv);
46
47 if (devad == MDIO_DEVAD_NONE) {
48 enetc_write(priv, ENETC_MDIO_CTL, ENETC_MDIO_CTL_READ |
49 (addr << 5) | reg);
50 } else {
51 enetc_write(priv, ENETC_MDIO_CTL, (addr << 5) + devad);
52 enetc_mdio_wait_bsy(priv);
53
54 enetc_write(priv, ENETC_MDIO_STAT, reg);
55 enetc_mdio_wait_bsy(priv);
56
57 enetc_write(priv, ENETC_MDIO_CTL, ENETC_MDIO_CTL_READ |
58 (addr << 5) | devad);
59 }
60
61 enetc_mdio_wait_bsy(priv);
62 if (enetc_read(priv, ENETC_MDIO_CFG) & ENETC_EMDIO_CFG_RD_ER)
63 return ENETC_MDIO_READ_ERR;
64
65 return enetc_read(priv, ENETC_MDIO_DATA);
66}
67
Alex Marginean38882ae2019-07-03 12:11:42 +030068int enetc_mdio_write_priv(struct enetc_mdio_priv *priv, int addr, int devad,
69 int reg, u16 val)
Alex Marginean02155392019-07-03 12:11:41 +030070{
71 if (devad == MDIO_DEVAD_NONE)
72 enetc_write(priv, ENETC_MDIO_CFG, ENETC_EMDIO_CFG_C22);
73 else
74 enetc_write(priv, ENETC_MDIO_CFG, ENETC_EMDIO_CFG_C45);
75 enetc_mdio_wait_bsy(priv);
76
77 if (devad != MDIO_DEVAD_NONE) {
78 enetc_write(priv, ENETC_MDIO_CTL, (addr << 5) + devad);
79 enetc_write(priv, ENETC_MDIO_STAT, reg);
80 } else {
81 enetc_write(priv, ENETC_MDIO_CTL, (addr << 5) + reg);
82 }
83 enetc_mdio_wait_bsy(priv);
84
85 enetc_write(priv, ENETC_MDIO_DATA, val);
86 enetc_mdio_wait_bsy(priv);
87
88 return 0;
89}
90
91/* DM wrappers */
92static int dm_enetc_mdio_read(struct udevice *dev, int addr, int devad, int reg)
93{
94 struct enetc_mdio_priv *priv = dev_get_priv(dev);
95
96 return enetc_mdio_read_priv(priv, addr, devad, reg);
97}
98
99static int dm_enetc_mdio_write(struct udevice *dev, int addr, int devad,
100 int reg, u16 val)
101{
102 struct enetc_mdio_priv *priv = dev_get_priv(dev);
103
104 return enetc_mdio_write_priv(priv, addr, devad, reg, val);
105}
106
107static const struct mdio_ops enetc_mdio_ops = {
108 .read = dm_enetc_mdio_read,
109 .write = dm_enetc_mdio_write,
110};
111
112static int enetc_mdio_bind(struct udevice *dev)
113{
114 char name[16];
115 static int eth_num_devices;
116
117 /*
118 * prefer using PCI function numbers to number interfaces, but these
119 * are only available if dts nodes are present. For PCI they are
120 * optional, handle that case too. Just in case some nodes are present
121 * and some are not, use different naming scheme - enetc-N based on
122 * PCI function # and enetc#N based on interface count
123 */
Simon Glassa7ece582020-12-19 10:40:14 -0700124 if (ofnode_valid(dev_ofnode(dev)))
Alex Marginean02155392019-07-03 12:11:41 +0300125 sprintf(name, "emdio-%u", PCI_FUNC(pci_get_devfn(dev)));
126 else
127 sprintf(name, "emdio#%u", eth_num_devices++);
128 device_set_name(dev, name);
129
130 return 0;
131}
132
133static int enetc_mdio_probe(struct udevice *dev)
134{
Alice Guo9a347952025-01-16 05:03:29 +0100135 struct pci_child_plat *pplat = dev_get_parent_plat(dev);
Alex Marginean02155392019-07-03 12:11:41 +0300136 struct enetc_mdio_priv *priv = dev_get_priv(dev);
Alice Guo9a347952025-01-16 05:03:29 +0100137 u16 cmd = PCI_COMMAND_MEMORY;
Alex Marginean02155392019-07-03 12:11:41 +0300138
Andrew Scull6520c822022-04-21 16:11:13 +0000139 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 +0300140 if (!priv->regs_base) {
141 enetc_dbg(dev, "failed to map BAR0\n");
142 return -EINVAL;
143 }
144
145 priv->regs_base += ENETC_MDIO_BASE;
146
Alice Guo9a347952025-01-16 05:03:29 +0100147 if (pplat->vendor == PCI_VENDOR_ID_PHILIPS) /* i.MX95 */
148 cmd |= PCI_COMMAND_MASTER;
149
150 dm_pci_clrset_config16(dev, PCI_COMMAND, 0, cmd);
Alex Marginean02155392019-07-03 12:11:41 +0300151
152 return 0;
153}
154
155U_BOOT_DRIVER(enetc_mdio) = {
156 .name = "enetc_mdio",
157 .id = UCLASS_MDIO,
158 .bind = enetc_mdio_bind,
159 .probe = enetc_mdio_probe,
160 .ops = &enetc_mdio_ops,
Simon Glass8a2b47f2020-12-03 16:55:17 -0700161 .priv_auto = sizeof(struct enetc_mdio_priv),
Alex Marginean02155392019-07-03 12:11:41 +0300162};
163
164static struct pci_device_id enetc_mdio_ids[] = {
165 { PCI_DEVICE(PCI_VENDOR_ID_FREESCALE, PCI_DEVICE_ID_ENETC_MDIO) },
Alice Guo9a347952025-01-16 05:03:29 +0100166 { PCI_DEVICE(PCI_VENDOR_ID_PHILIPS, PCI_DEVICE_ID_ENETC4_EMDIO) },
Alex Marginean881bcb62019-08-07 19:33:22 +0300167 { }
Alex Marginean02155392019-07-03 12:11:41 +0300168};
169
170U_BOOT_PCI_DEVICE(enetc_mdio, enetc_mdio_ids);