1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3 * (C) Copyright 2014
4 * Dirk Eibach, Guntermann & Drunck GmbH, dirk.eibach@gdsys.cc
5 */
6
7 #include <common.h>
8 #include <linux/delay.h>
9
10 #include <miiphy.h>
11 #ifdef CONFIG_GDSYS_LEGACY_DRIVERS
12 #include <gdsys_fpga.h>
13 #else
14 #include <fdtdec.h>
15 #include <dm.h>
16 #include <regmap.h>
17 #endif
18
19 #include "ihs_mdio.h"
20
21 #ifndef CONFIG_GDSYS_LEGACY_DRIVERS
22 enum {
23 REG_MDIO_CONTROL = 0x0,
24 REG_MDIO_ADDR_DATA = 0x2,
25 REG_MDIO_RX_DATA = 0x4,
26 };
27
read_reg(struct udevice * fpga,uint base,uint addr)28 static inline u16 read_reg(struct udevice *fpga, uint base, uint addr)
29 {
30 struct regmap *map;
31 u8 *ptr;
32
33 regmap_init_mem(dev_ofnode(fpga), &map);
34 ptr = regmap_get_range(map, 0);
35
36 return in_le16((u16 *)(ptr + base + addr));
37 }
38
write_reg(struct udevice * fpga,uint base,uint addr,u16 val)39 static inline void write_reg(struct udevice *fpga, uint base, uint addr,
40 u16 val)
41 {
42 struct regmap *map;
43 u8 *ptr;
44
45 regmap_init_mem(dev_ofnode(fpga), &map);
46 ptr = regmap_get_range(map, 0);
47
48 out_le16((u16 *)(ptr + base + addr), val);
49 }
50 #endif
51
read_control(struct ihs_mdio_info * info)52 static inline u16 read_control(struct ihs_mdio_info *info)
53 {
54 u16 val;
55 #ifdef CONFIG_GDSYS_LEGACY_DRIVERS
56 FPGA_GET_REG(info->fpga, mdio.control, &val);
57 #else
58 val = read_reg(info->fpga, info->base, REG_MDIO_CONTROL);
59 #endif
60 return val;
61 }
62
write_control(struct ihs_mdio_info * info,u16 val)63 static inline void write_control(struct ihs_mdio_info *info, u16 val)
64 {
65 #ifdef CONFIG_GDSYS_LEGACY_DRIVERS
66 FPGA_SET_REG(info->fpga, mdio.control, val);
67 #else
68 write_reg(info->fpga, info->base, REG_MDIO_CONTROL, val);
69 #endif
70 }
71
write_addr_data(struct ihs_mdio_info * info,u16 val)72 static inline void write_addr_data(struct ihs_mdio_info *info, u16 val)
73 {
74 #ifdef CONFIG_GDSYS_LEGACY_DRIVERS
75 FPGA_SET_REG(info->fpga, mdio.address_data, val);
76 #else
77 write_reg(info->fpga, info->base, REG_MDIO_ADDR_DATA, val);
78 #endif
79 }
80
read_rx_data(struct ihs_mdio_info * info)81 static inline u16 read_rx_data(struct ihs_mdio_info *info)
82 {
83 u16 val;
84 #ifdef CONFIG_GDSYS_LEGACY_DRIVERS
85 FPGA_GET_REG(info->fpga, mdio.rx_data, &val);
86 #else
87 val = read_reg(info->fpga, info->base, REG_MDIO_RX_DATA);
88 #endif
89 return val;
90 }
91
ihs_mdio_idle(struct mii_dev * bus)92 static 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 {
99 val = read_control(info);
100 udelay(100);
101 if (ctr++ > 10)
102 return -1;
103 } while (!(val & (1 << 12)));
104
105 return 0;
106 }
107
ihs_mdio_reset(struct mii_dev * bus)108 static int ihs_mdio_reset(struct mii_dev *bus)
109 {
110 ihs_mdio_idle(bus);
111
112 return 0;
113 }
114
ihs_mdio_read(struct mii_dev * bus,int addr,int dev_addr,int regnum)115 static 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
123 write_control(info,
124 ((addr & 0x1f) << 5) | (regnum & 0x1f) | (2 << 10));
125
126 /* wait for rx data available */
127 udelay(100);
128
129 val = read_rx_data(info);
130
131 return val;
132 }
133
ihs_mdio_write(struct mii_dev * bus,int addr,int dev_addr,int regnum,u16 value)134 static 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
141 write_addr_data(info, value);
142 write_control(info, ((addr & 0x1f) << 5) | (regnum & 0x1f) | (1 << 10));
143
144 return 0;
145 }
146
ihs_mdio_init(struct ihs_mdio_info * info)147 int 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;
159 strcpy(bus->name, info->name);
160
161 bus->priv = info;
162
163 return mdio_register(bus);
164 }
165