xref: /openbmc/u-boot/board/gdsys/common/ihs_mdio.c (revision c590e62d)
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