xref: /rk3399_rockchip-uboot/drivers/net/fm/memac_phy.c (revision cd348efa6c8c38cc95495a34d784f9ea159ca41d)
1111fd19eSRoy Zang /*
2111fd19eSRoy Zang  * Copyright 2012 Freescale Semiconductor, Inc.
3b21f87a3SAndy Fleming  *	Andy Fleming <afleming@gmail.com>
4111fd19eSRoy Zang  *	Roy Zang <tie-fei.zang@freescale.com>
5111fd19eSRoy Zang  *
61a459660SWolfgang Denk  * SPDX-License-Identifier:	GPL-2.0+
7111fd19eSRoy Zang  * Some part is taken from tsec.c
8111fd19eSRoy Zang  */
9111fd19eSRoy Zang #include <common.h>
10111fd19eSRoy Zang #include <miiphy.h>
11111fd19eSRoy Zang #include <phy.h>
12111fd19eSRoy Zang #include <asm/io.h>
13*cd348efaSShaohui Xie #include <fsl_memac.h>
14111fd19eSRoy Zang #include <fm_eth.h>
15111fd19eSRoy Zang 
16*cd348efaSShaohui Xie #ifdef CONFIG_SYS_MEMAC_LITTLE_ENDIAN
17*cd348efaSShaohui Xie #define memac_out_32(a, v)	out_le32(a, v)
18*cd348efaSShaohui Xie #define memac_clrbits_32(a, v)	clrbits_le32(a, v)
19*cd348efaSShaohui Xie #define memac_setbits_32(a, v)	setbits_le32(a, v)
20*cd348efaSShaohui Xie #else
21*cd348efaSShaohui Xie #define memac_out_32(a, v)	out_be32(a, v)
22*cd348efaSShaohui Xie #define memac_clrbits_32(a, v)	clrbits_be32(a, v)
23*cd348efaSShaohui Xie #define memac_setbits_32(a, v)	setbits_be32(a, v)
24*cd348efaSShaohui Xie #endif
25*cd348efaSShaohui Xie 
26*cd348efaSShaohui Xie static u32 memac_in_32(u32 *reg)
27*cd348efaSShaohui Xie {
28*cd348efaSShaohui Xie #ifdef CONFIG_SYS_MEMAC_LITTLE_ENDIAN
29*cd348efaSShaohui Xie 	return in_le32(reg);
30*cd348efaSShaohui Xie #else
31*cd348efaSShaohui Xie 	return in_be32(reg);
32*cd348efaSShaohui Xie #endif
33*cd348efaSShaohui Xie }
34*cd348efaSShaohui Xie 
35111fd19eSRoy Zang /*
36111fd19eSRoy Zang  * Write value to the PHY for this device to the register at regnum, waiting
37111fd19eSRoy Zang  * until the write is done before it returns.  All PHY configuration has to be
38111fd19eSRoy Zang  * done through the TSEC1 MIIM regs
39111fd19eSRoy Zang  */
40111fd19eSRoy Zang int memac_mdio_write(struct mii_dev *bus, int port_addr, int dev_addr,
41111fd19eSRoy Zang 			int regnum, u16 value)
42111fd19eSRoy Zang {
43111fd19eSRoy Zang 	u32 mdio_ctl;
44111fd19eSRoy Zang 	struct memac_mdio_controller *regs = bus->priv;
45111fd19eSRoy Zang 	u32 c45 = 1; /* Default to 10G interface */
46111fd19eSRoy Zang 
47111fd19eSRoy Zang 	if (dev_addr == MDIO_DEVAD_NONE) {
48111fd19eSRoy Zang 		c45 = 0; /* clause 22 */
49111fd19eSRoy Zang 		dev_addr = regnum & 0x1f;
50*cd348efaSShaohui Xie 		memac_clrbits_32(&regs->mdio_stat, MDIO_STAT_ENC);
513a7ed5aaSShaohui Xie 	} else
52*cd348efaSShaohui Xie 		memac_setbits_32(&regs->mdio_stat, MDIO_STAT_ENC);
53111fd19eSRoy Zang 
54111fd19eSRoy Zang 	/* Wait till the bus is free */
55*cd348efaSShaohui Xie 	while ((memac_in_32(&regs->mdio_stat)) & MDIO_STAT_BSY)
56111fd19eSRoy Zang 		;
57111fd19eSRoy Zang 
58111fd19eSRoy Zang 	/* Set the port and dev addr */
59111fd19eSRoy Zang 	mdio_ctl = MDIO_CTL_PORT_ADDR(port_addr) | MDIO_CTL_DEV_ADDR(dev_addr);
60*cd348efaSShaohui Xie 	memac_out_32(&regs->mdio_ctl, mdio_ctl);
61111fd19eSRoy Zang 
62111fd19eSRoy Zang 	/* Set the register address */
63111fd19eSRoy Zang 	if (c45)
64*cd348efaSShaohui Xie 		memac_out_32(&regs->mdio_addr, regnum & 0xffff);
65111fd19eSRoy Zang 
66111fd19eSRoy Zang 	/* Wait till the bus is free */
67*cd348efaSShaohui Xie 	while ((memac_in_32(&regs->mdio_stat)) & MDIO_STAT_BSY)
68111fd19eSRoy Zang 		;
69111fd19eSRoy Zang 
70111fd19eSRoy Zang 	/* Write the value to the register */
71*cd348efaSShaohui Xie 	memac_out_32(&regs->mdio_data, MDIO_DATA(value));
72111fd19eSRoy Zang 
73111fd19eSRoy Zang 	/* Wait till the MDIO write is complete */
74*cd348efaSShaohui Xie 	while ((memac_in_32(&regs->mdio_data)) & MDIO_DATA_BSY)
75111fd19eSRoy Zang 		;
76111fd19eSRoy Zang 
77111fd19eSRoy Zang 	return 0;
78111fd19eSRoy Zang }
79111fd19eSRoy Zang 
80111fd19eSRoy Zang /*
81111fd19eSRoy Zang  * Reads from register regnum in the PHY for device dev, returning the value.
82111fd19eSRoy Zang  * Clears miimcom first.  All PHY configuration has to be done through the
83111fd19eSRoy Zang  * TSEC1 MIIM regs
84111fd19eSRoy Zang  */
85111fd19eSRoy Zang int memac_mdio_read(struct mii_dev *bus, int port_addr, int dev_addr,
86111fd19eSRoy Zang 			int regnum)
87111fd19eSRoy Zang {
88111fd19eSRoy Zang 	u32 mdio_ctl;
89111fd19eSRoy Zang 	struct memac_mdio_controller *regs = bus->priv;
90111fd19eSRoy Zang 	u32 c45 = 1;
91111fd19eSRoy Zang 
92111fd19eSRoy Zang 	if (dev_addr == MDIO_DEVAD_NONE) {
93ff5fb2a3SShaohui Xie 		if (!strcmp(bus->name, DEFAULT_FM_TGEC_MDIO_NAME))
94ff5fb2a3SShaohui Xie 			return 0xffff;
95111fd19eSRoy Zang 		c45 = 0; /* clause 22 */
96111fd19eSRoy Zang 		dev_addr = regnum & 0x1f;
97*cd348efaSShaohui Xie 		memac_clrbits_32(&regs->mdio_stat, MDIO_STAT_ENC);
983a7ed5aaSShaohui Xie 	} else
99*cd348efaSShaohui Xie 		memac_setbits_32(&regs->mdio_stat, MDIO_STAT_ENC);
100111fd19eSRoy Zang 
101111fd19eSRoy Zang 	/* Wait till the bus is free */
102*cd348efaSShaohui Xie 	while ((memac_in_32(&regs->mdio_stat)) & MDIO_STAT_BSY)
103111fd19eSRoy Zang 		;
104111fd19eSRoy Zang 
105111fd19eSRoy Zang 	/* Set the Port and Device Addrs */
106111fd19eSRoy Zang 	mdio_ctl = MDIO_CTL_PORT_ADDR(port_addr) | MDIO_CTL_DEV_ADDR(dev_addr);
107*cd348efaSShaohui Xie 	memac_out_32(&regs->mdio_ctl, mdio_ctl);
108111fd19eSRoy Zang 
109111fd19eSRoy Zang 	/* Set the register address */
110111fd19eSRoy Zang 	if (c45)
111*cd348efaSShaohui Xie 		memac_out_32(&regs->mdio_addr, regnum & 0xffff);
112111fd19eSRoy Zang 
113111fd19eSRoy Zang 	/* Wait till the bus is free */
114*cd348efaSShaohui Xie 	while ((memac_in_32(&regs->mdio_stat)) & MDIO_STAT_BSY)
115111fd19eSRoy Zang 		;
116111fd19eSRoy Zang 
117111fd19eSRoy Zang 	/* Initiate the read */
118111fd19eSRoy Zang 	mdio_ctl |= MDIO_CTL_READ;
119*cd348efaSShaohui Xie 	memac_out_32(&regs->mdio_ctl, mdio_ctl);
120111fd19eSRoy Zang 
121111fd19eSRoy Zang 	/* Wait till the MDIO write is complete */
122*cd348efaSShaohui Xie 	while ((memac_in_32(&regs->mdio_data)) & MDIO_DATA_BSY)
123111fd19eSRoy Zang 		;
124111fd19eSRoy Zang 
125111fd19eSRoy Zang 	/* Return all Fs if nothing was there */
126*cd348efaSShaohui Xie 	if (memac_in_32(&regs->mdio_stat) & MDIO_STAT_RD_ER)
127111fd19eSRoy Zang 		return 0xffff;
128111fd19eSRoy Zang 
129*cd348efaSShaohui Xie 	return memac_in_32(&regs->mdio_data) & 0xffff;
130111fd19eSRoy Zang }
131111fd19eSRoy Zang 
132111fd19eSRoy Zang int memac_mdio_reset(struct mii_dev *bus)
133111fd19eSRoy Zang {
134111fd19eSRoy Zang 	return 0;
135111fd19eSRoy Zang }
136111fd19eSRoy Zang 
137111fd19eSRoy Zang int fm_memac_mdio_init(bd_t *bis, struct memac_mdio_info *info)
138111fd19eSRoy Zang {
139111fd19eSRoy Zang 	struct mii_dev *bus = mdio_alloc();
140111fd19eSRoy Zang 
141111fd19eSRoy Zang 	if (!bus) {
142111fd19eSRoy Zang 		printf("Failed to allocate FM TGEC MDIO bus\n");
143111fd19eSRoy Zang 		return -1;
144111fd19eSRoy Zang 	}
145111fd19eSRoy Zang 
146111fd19eSRoy Zang 	bus->read = memac_mdio_read;
147111fd19eSRoy Zang 	bus->write = memac_mdio_write;
148111fd19eSRoy Zang 	bus->reset = memac_mdio_reset;
149111fd19eSRoy Zang 	sprintf(bus->name, info->name);
150111fd19eSRoy Zang 
151111fd19eSRoy Zang 	bus->priv = info->regs;
152111fd19eSRoy Zang 
1532ee6c52eSPriyanka Jain 	/*
1542ee6c52eSPriyanka Jain 	 * On some platforms like B4860, default value of MDIO_CLK_DIV bits
1552ee6c52eSPriyanka Jain 	 * in mdio_stat(mdio_cfg) register generates MDIO clock too high
1562ee6c52eSPriyanka Jain 	 * (much higher than 2.5MHz), violating the IEEE specs.
1572ee6c52eSPriyanka Jain 	 * On other platforms like T1040, default value of MDIO_CLK_DIV bits
1582ee6c52eSPriyanka Jain 	 * is zero, so MDIO clock is disabled.
1592ee6c52eSPriyanka Jain 	 * So, for proper functioning of MDIO, MDIO_CLK_DIV bits needs to
1602ee6c52eSPriyanka Jain 	 * be properly initialized.
161ae6b4583SShaohui Xie 	 * NEG bit default should be '1' as per FMAN-v3 RM, but on platform
162ae6b4583SShaohui Xie 	 * like T2080QDS, this bit default is '0', which leads to MDIO failure
163ae6b4583SShaohui Xie 	 * on XAUI PHY, so set this bit definitely.
1642ee6c52eSPriyanka Jain 	 */
165*cd348efaSShaohui Xie 	memac_setbits_32(
166*cd348efaSShaohui Xie 		&((struct memac_mdio_controller *)info->regs)->mdio_stat,
167ae6b4583SShaohui Xie 		MDIO_STAT_CLKDIV(258) | MDIO_STAT_NEG);
1682ee6c52eSPriyanka Jain 
169111fd19eSRoy Zang 	return mdio_register(bus);
170111fd19eSRoy Zang }
171