1 /*
2  * Copyright 2008-2013 Freescale Semiconductor Inc.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions are met:
6  *     * Redistributions of source code must retain the above copyright
7  *       notice, this list of conditions and the following disclaimer.
8  *     * Redistributions in binary form must reproduce the above copyright
9  *       notice, this list of conditions and the following disclaimer in the
10  *       documentation and/or other materials provided with the distribution.
11  *     * Neither the name of Freescale Semiconductor nor the
12  *       names of its contributors may be used to endorse or promote products
13  *       derived from this software without specific prior written permission.
14  *
15  *
16  * ALTERNATIVELY, this software may be distributed under the terms of the
17  * GNU General Public License ("GPL") as published by the Free Software
18  * Foundation, either version 2 of that License or (at your option) any
19  * later version.
20  *
21  * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY
22  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
23  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
24  * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY
25  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
26  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
27  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
28  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
30  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31  */
32 
33 
34 #include "common/general.h"
35 #include "fsl_fman_dtsec_mii_acc.h"
36 
37 
38 /**
39  * dtsec_mii_get_div() - calculates the value of the dtsec mii divider
40  * @dtsec_freq:		dtsec clock frequency (in Mhz)
41  *
42  * This function calculates the dtsec mii clock divider that determines
43  * the MII MDC clock. MII MDC clock will be set to work in the range
44  * of 1.5 to 2.5Mhz
45  * The output of this function is the value of MIIMCFG[MgmtClk] which
46  * implicitly determines the divider value.
47  * Note: the dTSEC system clock is equal to 1/2 of the FMan clock.
48  *
49  * The table below which reflects dtsec_mii_get_div() functionality
50  * shows the relations among dtsec_freq, MgmtClk, actual divider
51  * and the MII frequency:
52  *
53  * dtsec freq   MgmtClk     div        MII freq Mhz
54  * [0.....80]     1      (1/4)(1/8)    [0   to 2.5]
55  * [81...120]     2      (1/6)(1/8)    [1.6 to 2.5]
56  * [121..160]     3      (1/8)(1/8)    [1.8 to 2.5]
57  * [161..200]     4      (1/10)(1/8)   [2.0 to 2.5]
58  * [201..280]     5      (1/14)(1/8)   [1.8 to 2.5]
59  * [281..400]     6      (1/20)(1/8)   [1.1 to 2.5]
60  * [401..560]     7      (1/28)(1/8)   [1.8 to 2.5]
61  * [560..frq]     7      (1/28)(1/8)   [frq/224]
62  *
63  * Returns: the MIIMCFG[MgmtClk] appropriate value
64  */
65 
66 static uint8_t dtsec_mii_get_div(uint16_t dtsec_freq)
67 {
68 	uint16_t mgmt_clk;
69 
70 	if (dtsec_freq < 80) mgmt_clk = 1;
71 	else if (dtsec_freq < 120) mgmt_clk = 2;
72 	else if (dtsec_freq < 160) mgmt_clk = 3;
73 	else if (dtsec_freq < 200) mgmt_clk = 4;
74 	else if (dtsec_freq < 280) mgmt_clk = 5;
75 	else if (dtsec_freq < 400) mgmt_clk = 6;
76 	else mgmt_clk = 7;
77 
78 	return (uint8_t)mgmt_clk;
79 }
80 
81 void fman_dtsec_mii_reset(struct dtsec_mii_reg *regs)
82 {
83 	/* Reset the management interface */
84 	iowrite32be(ioread32be(&regs->miimcfg) | MIIMCFG_RESET_MGMT,
85 			&regs->miimcfg);
86 	iowrite32be(ioread32be(&regs->miimcfg) & ~MIIMCFG_RESET_MGMT,
87 			&regs->miimcfg);
88 }
89 
90 
91 int fman_dtsec_mii_write_reg(struct dtsec_mii_reg *regs, uint8_t addr,
92 		uint8_t reg, uint16_t data, uint16_t dtsec_freq)
93 {
94 	uint32_t	tmp;
95 
96 	/* Setup the MII Mgmt clock speed */
97 	iowrite32be((uint32_t)dtsec_mii_get_div(dtsec_freq), &regs->miimcfg);
98 	wmb();
99 
100 	/* Stop the MII management read cycle */
101 	iowrite32be(0, &regs->miimcom);
102 	/* Dummy read to make sure MIIMCOM is written */
103 	tmp = ioread32be(&regs->miimcom);
104 	wmb();
105 
106 	/* Setting up MII Management Address Register */
107 	tmp = (uint32_t)((addr << MIIMADD_PHY_ADDR_SHIFT) | reg);
108 	iowrite32be(tmp, &regs->miimadd);
109 	wmb();
110 
111 	/* Setting up MII Management Control Register with data */
112 	iowrite32be((uint32_t)data, &regs->miimcon);
113 	/* Dummy read to make sure MIIMCON is written */
114 	tmp = ioread32be(&regs->miimcon);
115 	wmb();
116 
117 	/* Wait until MII management write is complete */
118 	/* todo: a timeout could be useful here */
119 	while ((ioread32be(&regs->miimind)) & MIIMIND_BUSY)
120 		/* busy wait */;
121 
122 	return 0;
123 }
124 
125 int fman_dtsec_mii_read_reg(struct dtsec_mii_reg *regs, uint8_t  addr,
126 		uint8_t reg, uint16_t *data, uint16_t dtsec_freq)
127 {
128 	uint32_t	tmp;
129 
130 	/* Setup the MII Mgmt clock speed */
131 	iowrite32be((uint32_t)dtsec_mii_get_div(dtsec_freq), &regs->miimcfg);
132 	wmb();
133 
134 	/* Setting up the MII Management Address Register */
135 	tmp = (uint32_t)((addr << MIIMADD_PHY_ADDR_SHIFT) | reg);
136 	iowrite32be(tmp, &regs->miimadd);
137 	wmb();
138 
139 	/* Perform an MII management read cycle */
140 	iowrite32be(MIIMCOM_READ_CYCLE, &regs->miimcom);
141 	/* Dummy read to make sure MIIMCOM is written */
142 	tmp = ioread32be(&regs->miimcom);
143 	wmb();
144 
145 	/* Wait until MII management read is complete */
146 	/* todo: a timeout could be useful here */
147 	while ((ioread32be(&regs->miimind)) & MIIMIND_BUSY)
148 		/* busy wait */;
149 
150 	/* Read MII management status  */
151 	*data = (uint16_t)ioread32be(&regs->miimstat);
152 	wmb();
153 
154 	iowrite32be(0, &regs->miimcom);
155 	/* Dummy read to make sure MIIMCOM is written */
156 	tmp = ioread32be(&regs->miimcom);
157 
158 	if (*data == 0xffff)
159 		return -ENXIO;
160 
161 	return 0;
162 }
163 
164