blob: 5f1215e9e8a65a34e7d9ca6363380a408ce9460e [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
7#include <common.h>
Simon Glassdbd79542020-05-10 11:40:11 -06008#include <linux/delay.h>
Dirk Eibachf74a0272014-11-13 19:21:18 +01009
Dirk Eibachf74a0272014-11-13 19:21:18 +010010#include <miiphy.h>
Mario Six29637212018-04-27 14:52:10 +020011#ifdef CONFIG_GDSYS_LEGACY_DRIVERS
12#include <gdsys_fpga.h>
13#else
14#include <fdtdec.h>
Mario Six7720ba02019-01-28 09:49:33 +010015#include <dm.h>
Mario Six29637212018-04-27 14:52:10 +020016#include <regmap.h>
17#endif
Dirk Eibachf74a0272014-11-13 19:21:18 +010018
19#include "ihs_mdio.h"
20
Mario Six29637212018-04-27 14:52:10 +020021#ifndef CONFIG_GDSYS_LEGACY_DRIVERS
22enum {
23 REG_MDIO_CONTROL = 0x0,
24 REG_MDIO_ADDR_DATA = 0x2,
25 REG_MDIO_RX_DATA = 0x4,
26};
27
28static inline u16 read_reg(struct udevice *fpga, uint base, uint addr)
29{
30 struct regmap *map;
31 u8 *ptr;
32
Mario Six7720ba02019-01-28 09:49:33 +010033 regmap_init_mem(dev_ofnode(fpga), &map);
Mario Six29637212018-04-27 14:52:10 +020034 ptr = regmap_get_range(map, 0);
35
36 return in_le16((u16 *)(ptr + base + addr));
37}
38
39static inline void write_reg(struct udevice *fpga, uint base, uint addr,
40 u16 val)
41{
42 struct regmap *map;
43 u8 *ptr;
44
Mario Six7720ba02019-01-28 09:49:33 +010045 regmap_init_mem(dev_ofnode(fpga), &map);
Mario Six29637212018-04-27 14:52:10 +020046 ptr = regmap_get_range(map, 0);
47
48 out_le16((u16 *)(ptr + base + addr), val);
49}
50#endif
51
Mario Six9a95ba62018-04-27 14:52:09 +020052static inline u16 read_control(struct ihs_mdio_info *info)
53{
54 u16 val;
Mario Six29637212018-04-27 14:52:10 +020055#ifdef CONFIG_GDSYS_LEGACY_DRIVERS
Mario Six9a95ba62018-04-27 14:52:09 +020056 FPGA_GET_REG(info->fpga, mdio.control, &val);
Mario Six29637212018-04-27 14:52:10 +020057#else
58 val = read_reg(info->fpga, info->base, REG_MDIO_CONTROL);
59#endif
Mario Six9a95ba62018-04-27 14:52:09 +020060 return val;
61}
62
63static inline void write_control(struct ihs_mdio_info *info, u16 val)
64{
Mario Six29637212018-04-27 14:52:10 +020065#ifdef CONFIG_GDSYS_LEGACY_DRIVERS
Mario Six9a95ba62018-04-27 14:52:09 +020066 FPGA_SET_REG(info->fpga, mdio.control, val);
Mario Six29637212018-04-27 14:52:10 +020067#else
68 write_reg(info->fpga, info->base, REG_MDIO_CONTROL, val);
69#endif
Mario Six9a95ba62018-04-27 14:52:09 +020070}
71
72static inline void write_addr_data(struct ihs_mdio_info *info, u16 val)
73{
Mario Six29637212018-04-27 14:52:10 +020074#ifdef CONFIG_GDSYS_LEGACY_DRIVERS
Mario Six9a95ba62018-04-27 14:52:09 +020075 FPGA_SET_REG(info->fpga, mdio.address_data, val);
Mario Six29637212018-04-27 14:52:10 +020076#else
77 write_reg(info->fpga, info->base, REG_MDIO_ADDR_DATA, val);
78#endif
Mario Six9a95ba62018-04-27 14:52:09 +020079}
80
81static inline u16 read_rx_data(struct ihs_mdio_info *info)
82{
83 u16 val;
Mario Six29637212018-04-27 14:52:10 +020084#ifdef CONFIG_GDSYS_LEGACY_DRIVERS
Mario Six9a95ba62018-04-27 14:52:09 +020085 FPGA_GET_REG(info->fpga, mdio.rx_data, &val);
Mario Six29637212018-04-27 14:52:10 +020086#else
87 val = read_reg(info->fpga, info->base, REG_MDIO_RX_DATA);
88#endif
Mario Six9a95ba62018-04-27 14:52:09 +020089 return val;
90}
91
Dirk Eibachf74a0272014-11-13 19:21:18 +010092static int ihs_mdio_idle(struct mii_dev *bus)
93{
94 struct ihs_mdio_info *info = bus->priv;
95 u16 val;
96 unsigned int ctr = 0;
97
98 do {
Mario Six9a95ba62018-04-27 14:52:09 +020099 val = read_control(info);
Dirk Eibachf74a0272014-11-13 19:21:18 +0100100 udelay(100);
101 if (ctr++ > 10)
102 return -1;
103 } while (!(val & (1 << 12)));
104
105 return 0;
106}
107
108static int ihs_mdio_reset(struct mii_dev *bus)
109{
110 ihs_mdio_idle(bus);
111
112 return 0;
113}
114
115static int ihs_mdio_read(struct mii_dev *bus, int addr, int dev_addr,
116 int regnum)
117{
118 struct ihs_mdio_info *info = bus->priv;
119 u16 val;
120
121 ihs_mdio_idle(bus);
122
Mario Six9a95ba62018-04-27 14:52:09 +0200123 write_control(info,
124 ((addr & 0x1f) << 5) | (regnum & 0x1f) | (2 << 10));
Dirk Eibachf74a0272014-11-13 19:21:18 +0100125
126 /* wait for rx data available */
127 udelay(100);
128
Mario Six9a95ba62018-04-27 14:52:09 +0200129 val = read_rx_data(info);
Dirk Eibachf74a0272014-11-13 19:21:18 +0100130
131 return val;
132}
133
134static int ihs_mdio_write(struct mii_dev *bus, int addr, int dev_addr,
135 int regnum, u16 value)
136{
137 struct ihs_mdio_info *info = bus->priv;
138
139 ihs_mdio_idle(bus);
140
Mario Six9a95ba62018-04-27 14:52:09 +0200141 write_addr_data(info, value);
142 write_control(info, ((addr & 0x1f) << 5) | (regnum & 0x1f) | (1 << 10));
Dirk Eibachf74a0272014-11-13 19:21:18 +0100143
144 return 0;
145}
146
147int ihs_mdio_init(struct ihs_mdio_info *info)
148{
149 struct mii_dev *bus = mdio_alloc();
150
151 if (!bus) {
152 printf("Failed to allocate FSL MDIO bus\n");
153 return -1;
154 }
155
156 bus->read = ihs_mdio_read;
157 bus->write = ihs_mdio_write;
158 bus->reset = ihs_mdio_reset;
Ben Whitten34fd6c92015-12-30 13:05:58 +0000159 strcpy(bus->name, info->name);
Dirk Eibachf74a0272014-11-13 19:21:18 +0100160
161 bus->priv = info;
162
163 return mdio_register(bus);
164}