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