blob: a814566beaf0e5055b7b65135cab7b2ef9880b81 [file] [log] [blame]
Tom Rini10e47792018-05-06 17:58:06 -04001// SPDX-License-Identifier: GPL-2.0+
Dirk Eibachf74a0272014-11-13 19:21:18 +01002/*
3 * (C) Copyright 2014
Mario Sixb4893582018-03-06 08:04:58 +01004 * Dirk Eibach, Guntermann & Drunck GmbH, dirk.eibach@gdsys.cc
Dirk Eibachf74a0272014-11-13 19:21:18 +01005 */
6
Simon Glassdbd79542020-05-10 11:40:11 -06007#include <linux/delay.h>
Dirk Eibachf74a0272014-11-13 19:21:18 +01008
Dirk Eibachf74a0272014-11-13 19:21:18 +01009#include <miiphy.h>
Mario Six29637212018-04-27 14:52:10 +020010#ifdef CONFIG_GDSYS_LEGACY_DRIVERS
11#include <gdsys_fpga.h>
12#else
13#include <fdtdec.h>
Mario Six7720ba02019-01-28 09:49:33 +010014#include <dm.h>
Mario Six29637212018-04-27 14:52:10 +020015#include <regmap.h>
16#endif
Dirk Eibachf74a0272014-11-13 19:21:18 +010017
18#include "ihs_mdio.h"
19
Mario Six29637212018-04-27 14:52:10 +020020#ifndef CONFIG_GDSYS_LEGACY_DRIVERS
21enum {
22 REG_MDIO_CONTROL = 0x0,
23 REG_MDIO_ADDR_DATA = 0x2,
24 REG_MDIO_RX_DATA = 0x4,
25};
26
27static inline u16 read_reg(struct udevice *fpga, uint base, uint addr)
28{
29 struct regmap *map;
30 u8 *ptr;
31
Mario Six7720ba02019-01-28 09:49:33 +010032 regmap_init_mem(dev_ofnode(fpga), &map);
Mario Six29637212018-04-27 14:52:10 +020033 ptr = regmap_get_range(map, 0);
34
35 return in_le16((u16 *)(ptr + base + addr));
36}
37
38static inline void write_reg(struct udevice *fpga, uint base, uint addr,
39 u16 val)
40{
41 struct regmap *map;
42 u8 *ptr;
43
Mario Six7720ba02019-01-28 09:49:33 +010044 regmap_init_mem(dev_ofnode(fpga), &map);
Mario Six29637212018-04-27 14:52:10 +020045 ptr = regmap_get_range(map, 0);
46
47 out_le16((u16 *)(ptr + base + addr), val);
48}
49#endif
50
Mario Six9a95ba62018-04-27 14:52:09 +020051static inline u16 read_control(struct ihs_mdio_info *info)
52{
53 u16 val;
Mario Six29637212018-04-27 14:52:10 +020054#ifdef CONFIG_GDSYS_LEGACY_DRIVERS
Mario Six9a95ba62018-04-27 14:52:09 +020055 FPGA_GET_REG(info->fpga, mdio.control, &val);
Mario Six29637212018-04-27 14:52:10 +020056#else
57 val = read_reg(info->fpga, info->base, REG_MDIO_CONTROL);
58#endif
Mario Six9a95ba62018-04-27 14:52:09 +020059 return val;
60}
61
62static inline void write_control(struct ihs_mdio_info *info, u16 val)
63{
Mario Six29637212018-04-27 14:52:10 +020064#ifdef CONFIG_GDSYS_LEGACY_DRIVERS
Mario Six9a95ba62018-04-27 14:52:09 +020065 FPGA_SET_REG(info->fpga, mdio.control, val);
Mario Six29637212018-04-27 14:52:10 +020066#else
67 write_reg(info->fpga, info->base, REG_MDIO_CONTROL, val);
68#endif
Mario Six9a95ba62018-04-27 14:52:09 +020069}
70
71static inline void write_addr_data(struct ihs_mdio_info *info, u16 val)
72{
Mario Six29637212018-04-27 14:52:10 +020073#ifdef CONFIG_GDSYS_LEGACY_DRIVERS
Mario Six9a95ba62018-04-27 14:52:09 +020074 FPGA_SET_REG(info->fpga, mdio.address_data, val);
Mario Six29637212018-04-27 14:52:10 +020075#else
76 write_reg(info->fpga, info->base, REG_MDIO_ADDR_DATA, val);
77#endif
Mario Six9a95ba62018-04-27 14:52:09 +020078}
79
80static inline u16 read_rx_data(struct ihs_mdio_info *info)
81{
82 u16 val;
Mario Six29637212018-04-27 14:52:10 +020083#ifdef CONFIG_GDSYS_LEGACY_DRIVERS
Mario Six9a95ba62018-04-27 14:52:09 +020084 FPGA_GET_REG(info->fpga, mdio.rx_data, &val);
Mario Six29637212018-04-27 14:52:10 +020085#else
86 val = read_reg(info->fpga, info->base, REG_MDIO_RX_DATA);
87#endif
Mario Six9a95ba62018-04-27 14:52:09 +020088 return val;
89}
90
Dirk Eibachf74a0272014-11-13 19:21:18 +010091static int ihs_mdio_idle(struct mii_dev *bus)
92{
93 struct ihs_mdio_info *info = bus->priv;
94 u16 val;
95 unsigned int ctr = 0;
96
97 do {
Mario Six9a95ba62018-04-27 14:52:09 +020098 val = read_control(info);
Dirk Eibachf74a0272014-11-13 19:21:18 +010099 udelay(100);
100 if (ctr++ > 10)
101 return -1;
102 } while (!(val & (1 << 12)));
103
104 return 0;
105}
106
107static int ihs_mdio_reset(struct mii_dev *bus)
108{
109 ihs_mdio_idle(bus);
110
111 return 0;
112}
113
114static int ihs_mdio_read(struct mii_dev *bus, int addr, int dev_addr,
115 int regnum)
116{
117 struct ihs_mdio_info *info = bus->priv;
118 u16 val;
119
120 ihs_mdio_idle(bus);
121
Mario Six9a95ba62018-04-27 14:52:09 +0200122 write_control(info,
123 ((addr & 0x1f) << 5) | (regnum & 0x1f) | (2 << 10));
Dirk Eibachf74a0272014-11-13 19:21:18 +0100124
125 /* wait for rx data available */
126 udelay(100);
127
Mario Six9a95ba62018-04-27 14:52:09 +0200128 val = read_rx_data(info);
Dirk Eibachf74a0272014-11-13 19:21:18 +0100129
130 return val;
131}
132
133static int ihs_mdio_write(struct mii_dev *bus, int addr, int dev_addr,
134 int regnum, u16 value)
135{
136 struct ihs_mdio_info *info = bus->priv;
137
138 ihs_mdio_idle(bus);
139
Mario Six9a95ba62018-04-27 14:52:09 +0200140 write_addr_data(info, value);
141 write_control(info, ((addr & 0x1f) << 5) | (regnum & 0x1f) | (1 << 10));
Dirk Eibachf74a0272014-11-13 19:21:18 +0100142
143 return 0;
144}
145
146int ihs_mdio_init(struct ihs_mdio_info *info)
147{
148 struct mii_dev *bus = mdio_alloc();
149
150 if (!bus) {
151 printf("Failed to allocate FSL MDIO bus\n");
152 return -1;
153 }
154
155 bus->read = ihs_mdio_read;
156 bus->write = ihs_mdio_write;
157 bus->reset = ihs_mdio_reset;
Ben Whitten34fd6c92015-12-30 13:05:58 +0000158 strcpy(bus->name, info->name);
Dirk Eibachf74a0272014-11-13 19:21:18 +0100159
160 bus->priv = info;
161
162 return mdio_register(bus);
163}