183d290c5STom Rini // SPDX-License-Identifier: GPL-2.0+
250dcf89dSDirk Eibach /*
350dcf89dSDirk Eibach * (C) Copyright 2014
4d38826a3SMario Six * Dirk Eibach, Guntermann & Drunck GmbH, dirk.eibach@gdsys.cc
550dcf89dSDirk Eibach */
650dcf89dSDirk Eibach
750dcf89dSDirk Eibach #include <common.h>
850dcf89dSDirk Eibach
950dcf89dSDirk Eibach #include <miiphy.h>
10*9a519dfeSMario Six #ifdef CONFIG_GDSYS_LEGACY_DRIVERS
11*9a519dfeSMario Six #include <gdsys_fpga.h>
12*9a519dfeSMario Six #else
13*9a519dfeSMario Six #include <fdtdec.h>
14*9a519dfeSMario Six #include <regmap.h>
15*9a519dfeSMario Six #endif
1650dcf89dSDirk Eibach
1750dcf89dSDirk Eibach #include "ihs_mdio.h"
1850dcf89dSDirk Eibach
19*9a519dfeSMario Six #ifndef CONFIG_GDSYS_LEGACY_DRIVERS
20*9a519dfeSMario Six enum {
21*9a519dfeSMario Six REG_MDIO_CONTROL = 0x0,
22*9a519dfeSMario Six REG_MDIO_ADDR_DATA = 0x2,
23*9a519dfeSMario Six REG_MDIO_RX_DATA = 0x4,
24*9a519dfeSMario Six };
25*9a519dfeSMario Six
read_reg(struct udevice * fpga,uint base,uint addr)26*9a519dfeSMario Six static inline u16 read_reg(struct udevice *fpga, uint base, uint addr)
27*9a519dfeSMario Six {
28*9a519dfeSMario Six struct regmap *map;
29*9a519dfeSMario Six u8 *ptr;
30*9a519dfeSMario Six
31*9a519dfeSMario Six regmap_init_mem(fpga, &map);
32*9a519dfeSMario Six ptr = regmap_get_range(map, 0);
33*9a519dfeSMario Six
34*9a519dfeSMario Six return in_le16((u16 *)(ptr + base + addr));
35*9a519dfeSMario Six }
36*9a519dfeSMario Six
write_reg(struct udevice * fpga,uint base,uint addr,u16 val)37*9a519dfeSMario Six static inline void write_reg(struct udevice *fpga, uint base, uint addr,
38*9a519dfeSMario Six u16 val)
39*9a519dfeSMario Six {
40*9a519dfeSMario Six struct regmap *map;
41*9a519dfeSMario Six u8 *ptr;
42*9a519dfeSMario Six
43*9a519dfeSMario Six regmap_init_mem(fpga, &map);
44*9a519dfeSMario Six ptr = regmap_get_range(map, 0);
45*9a519dfeSMario Six
46*9a519dfeSMario Six out_le16((u16 *)(ptr + base + addr), val);
47*9a519dfeSMario Six }
48*9a519dfeSMario Six #endif
49*9a519dfeSMario Six
read_control(struct ihs_mdio_info * info)509139ac9dSMario Six static inline u16 read_control(struct ihs_mdio_info *info)
519139ac9dSMario Six {
529139ac9dSMario Six u16 val;
53*9a519dfeSMario Six #ifdef CONFIG_GDSYS_LEGACY_DRIVERS
549139ac9dSMario Six FPGA_GET_REG(info->fpga, mdio.control, &val);
55*9a519dfeSMario Six #else
56*9a519dfeSMario Six val = read_reg(info->fpga, info->base, REG_MDIO_CONTROL);
57*9a519dfeSMario Six #endif
589139ac9dSMario Six return val;
599139ac9dSMario Six }
609139ac9dSMario Six
write_control(struct ihs_mdio_info * info,u16 val)619139ac9dSMario Six static inline void write_control(struct ihs_mdio_info *info, u16 val)
629139ac9dSMario Six {
63*9a519dfeSMario Six #ifdef CONFIG_GDSYS_LEGACY_DRIVERS
649139ac9dSMario Six FPGA_SET_REG(info->fpga, mdio.control, val);
65*9a519dfeSMario Six #else
66*9a519dfeSMario Six write_reg(info->fpga, info->base, REG_MDIO_CONTROL, val);
67*9a519dfeSMario Six #endif
689139ac9dSMario Six }
699139ac9dSMario Six
write_addr_data(struct ihs_mdio_info * info,u16 val)709139ac9dSMario Six static inline void write_addr_data(struct ihs_mdio_info *info, u16 val)
719139ac9dSMario Six {
72*9a519dfeSMario Six #ifdef CONFIG_GDSYS_LEGACY_DRIVERS
739139ac9dSMario Six FPGA_SET_REG(info->fpga, mdio.address_data, val);
74*9a519dfeSMario Six #else
75*9a519dfeSMario Six write_reg(info->fpga, info->base, REG_MDIO_ADDR_DATA, val);
76*9a519dfeSMario Six #endif
779139ac9dSMario Six }
789139ac9dSMario Six
read_rx_data(struct ihs_mdio_info * info)799139ac9dSMario Six static inline u16 read_rx_data(struct ihs_mdio_info *info)
809139ac9dSMario Six {
819139ac9dSMario Six u16 val;
82*9a519dfeSMario Six #ifdef CONFIG_GDSYS_LEGACY_DRIVERS
839139ac9dSMario Six FPGA_GET_REG(info->fpga, mdio.rx_data, &val);
84*9a519dfeSMario Six #else
85*9a519dfeSMario Six val = read_reg(info->fpga, info->base, REG_MDIO_RX_DATA);
86*9a519dfeSMario Six #endif
879139ac9dSMario Six return val;
889139ac9dSMario Six }
899139ac9dSMario Six
ihs_mdio_idle(struct mii_dev * bus)9050dcf89dSDirk Eibach static int ihs_mdio_idle(struct mii_dev *bus)
9150dcf89dSDirk Eibach {
9250dcf89dSDirk Eibach struct ihs_mdio_info *info = bus->priv;
9350dcf89dSDirk Eibach u16 val;
9450dcf89dSDirk Eibach unsigned int ctr = 0;
9550dcf89dSDirk Eibach
9650dcf89dSDirk Eibach do {
979139ac9dSMario Six val = read_control(info);
9850dcf89dSDirk Eibach udelay(100);
9950dcf89dSDirk Eibach if (ctr++ > 10)
10050dcf89dSDirk Eibach return -1;
10150dcf89dSDirk Eibach } while (!(val & (1 << 12)));
10250dcf89dSDirk Eibach
10350dcf89dSDirk Eibach return 0;
10450dcf89dSDirk Eibach }
10550dcf89dSDirk Eibach
ihs_mdio_reset(struct mii_dev * bus)10650dcf89dSDirk Eibach static int ihs_mdio_reset(struct mii_dev *bus)
10750dcf89dSDirk Eibach {
10850dcf89dSDirk Eibach ihs_mdio_idle(bus);
10950dcf89dSDirk Eibach
11050dcf89dSDirk Eibach return 0;
11150dcf89dSDirk Eibach }
11250dcf89dSDirk Eibach
ihs_mdio_read(struct mii_dev * bus,int addr,int dev_addr,int regnum)11350dcf89dSDirk Eibach static int ihs_mdio_read(struct mii_dev *bus, int addr, int dev_addr,
11450dcf89dSDirk Eibach int regnum)
11550dcf89dSDirk Eibach {
11650dcf89dSDirk Eibach struct ihs_mdio_info *info = bus->priv;
11750dcf89dSDirk Eibach u16 val;
11850dcf89dSDirk Eibach
11950dcf89dSDirk Eibach ihs_mdio_idle(bus);
12050dcf89dSDirk Eibach
1219139ac9dSMario Six write_control(info,
12250dcf89dSDirk Eibach ((addr & 0x1f) << 5) | (regnum & 0x1f) | (2 << 10));
12350dcf89dSDirk Eibach
12450dcf89dSDirk Eibach /* wait for rx data available */
12550dcf89dSDirk Eibach udelay(100);
12650dcf89dSDirk Eibach
1279139ac9dSMario Six val = read_rx_data(info);
12850dcf89dSDirk Eibach
12950dcf89dSDirk Eibach return val;
13050dcf89dSDirk Eibach }
13150dcf89dSDirk Eibach
ihs_mdio_write(struct mii_dev * bus,int addr,int dev_addr,int regnum,u16 value)13250dcf89dSDirk Eibach static int ihs_mdio_write(struct mii_dev *bus, int addr, int dev_addr,
13350dcf89dSDirk Eibach int regnum, u16 value)
13450dcf89dSDirk Eibach {
13550dcf89dSDirk Eibach struct ihs_mdio_info *info = bus->priv;
13650dcf89dSDirk Eibach
13750dcf89dSDirk Eibach ihs_mdio_idle(bus);
13850dcf89dSDirk Eibach
1399139ac9dSMario Six write_addr_data(info, value);
1409139ac9dSMario Six write_control(info, ((addr & 0x1f) << 5) | (regnum & 0x1f) | (1 << 10));
14150dcf89dSDirk Eibach
14250dcf89dSDirk Eibach return 0;
14350dcf89dSDirk Eibach }
14450dcf89dSDirk Eibach
ihs_mdio_init(struct ihs_mdio_info * info)14550dcf89dSDirk Eibach int ihs_mdio_init(struct ihs_mdio_info *info)
14650dcf89dSDirk Eibach {
14750dcf89dSDirk Eibach struct mii_dev *bus = mdio_alloc();
14850dcf89dSDirk Eibach
14950dcf89dSDirk Eibach if (!bus) {
15050dcf89dSDirk Eibach printf("Failed to allocate FSL MDIO bus\n");
15150dcf89dSDirk Eibach return -1;
15250dcf89dSDirk Eibach }
15350dcf89dSDirk Eibach
15450dcf89dSDirk Eibach bus->read = ihs_mdio_read;
15550dcf89dSDirk Eibach bus->write = ihs_mdio_write;
15650dcf89dSDirk Eibach bus->reset = ihs_mdio_reset;
157192bc694SBen Whitten strcpy(bus->name, info->name);
15850dcf89dSDirk Eibach
15950dcf89dSDirk Eibach bus->priv = info;
16050dcf89dSDirk Eibach
16150dcf89dSDirk Eibach return mdio_register(bus);
16250dcf89dSDirk Eibach }
163