source: rtems/c/src/lib/libbsp/arm/csb336/network/lan91c11x.c @ e56090ef

5
Last change on this file since e56090ef was c499856, checked in by Chris Johns <chrisj@…>, on 03/20/14 at 21:10:47

Change all references of rtems.com to rtems.org.

  • Property mode set to 100644
File size: 6.3 KB
Line 
1/**
2 * @file
3 *
4 * @ingroup arm_csb336
5 *
6 * @brief Helper functions for SMSC LAN91C11x
7 */
8
9/*
10 *  Helper functions for SMSC LAN91C11x
11 *
12 *  Copyright (c) 2004 by Cogent Computer Systems
13 *  Written by Jay Monkman <jtm@lopingdog.com>
14 *
15 *  The license and distribution terms for this file may be
16 *  found in the file LICENSE in this distribution or at
17 *  http://www.rtems.org/license/LICENSE.
18 */
19#include <rtems.h>
20#include "lan91c11x.h"
21
22uint16_t lan91c11x_read_reg(int reg)
23{
24    volatile uint16_t *ptr = (uint16_t *)LAN91C11X_BASE_ADDR;
25    uint16_t old_bank;
26    uint16_t val;
27    rtems_interrupt_level level;
28
29    rtems_interrupt_disable(level);
30
31    /* save the bank register */
32    old_bank = ptr[7] & 0x7;
33
34    /* set the bank register */
35    ptr[7] = (reg >> 4) & 0x7;
36
37    val = ptr[((reg & 0xf) >> 1)];
38
39    /* restore the bank register */
40    ptr[7] = old_bank;
41
42    rtems_interrupt_enable(level);
43    return val;
44}
45
46void lan91c11x_write_reg(int reg, uint16_t value)
47{
48    volatile uint16_t *ptr = (uint16_t *)LAN91C11X_BASE_ADDR;
49    uint16_t old_bank;
50    rtems_interrupt_level level;
51
52    rtems_interrupt_disable(level);
53
54    /* save the bank register */
55    old_bank = ptr[7] & 0x7;
56
57    /* set the bank register */
58    ptr[7] = (reg >> 4) & 0x7;
59
60    ptr[((reg & 0xf) >> 1)] = value;
61
62    /* restore the bank register */
63    ptr[7] = old_bank;
64
65    rtems_interrupt_enable(level);
66}
67
68uint16_t lan91c11x_read_reg_fast(int reg)
69{
70    volatile uint16_t *ptr = (uint16_t *)LAN91C11X_BASE_ADDR;
71    uint16_t val;
72
73    val = ptr[((reg & 0xf) >> 1)];
74
75    return val;
76}
77
78void lan91c11x_write_reg_fast(int reg, uint16_t value)
79{
80    volatile uint16_t *ptr = (uint16_t *)LAN91C11X_BASE_ADDR;
81
82    ptr[((reg & 0xf) >> 1)] = value;
83}
84
85
86uint16_t lan91c11x_read_phy_reg(int reg)
87{
88    int i;
89    uint16_t mask;
90    uint16_t bits[64];
91    int clk_idx = 0;
92    int input_idx = 0;
93    uint16_t phydata;
94
95    /* 32 consecutive ones on MDO to establish sync */
96    for (i = 0; i < 32; ++i) {
97        bits[clk_idx++] = LAN91C11X_MGMT_MDOE | LAN91C11X_MGMT_MDO;
98    }
99
100    /* Start code <01> */
101    bits[clk_idx++] = LAN91C11X_MGMT_MDOE;
102    bits[clk_idx++] = LAN91C11X_MGMT_MDOE | LAN91C11X_MGMT_MDO;
103
104    /* Read command <10> */
105    bits[clk_idx++] = LAN91C11X_MGMT_MDOE | LAN91C11X_MGMT_MDO;
106    bits[clk_idx++] = LAN91C11X_MGMT_MDOE;
107
108    /* Output the PHY address, msb first - Internal PHY is address 0 */
109    for (i = 0; i < 5; ++i) {
110        bits[clk_idx++] = LAN91C11X_MGMT_MDOE;
111    }
112
113    /* Output the phy register number, msb first */
114    mask = 0x10;
115    for (i = 0; i < 5; ++i) {
116        if (reg & mask) {
117            bits[clk_idx++] = LAN91C11X_MGMT_MDOE | LAN91C11X_MGMT_MDO;
118        } else {
119            bits[clk_idx++] = LAN91C11X_MGMT_MDOE;
120        }
121
122
123        /* Shift to next lowest bit */
124        mask >>= 1;
125    }
126
127    /* 1 bit time for turnaround */
128    bits[clk_idx++] = 0;
129
130    /* Input starts at this bit time */
131    input_idx = clk_idx;
132
133    /* Will input 16 bits */
134    for (i = 0; i < 16; ++i) {
135        bits[clk_idx++] = 0;
136    }
137
138    /* Final clock bit */
139    bits[clk_idx++] = 0;
140
141    /* Turn off all MII Interface bits */
142    lan91c11x_write_reg(LAN91C11X_MGMT,
143                        lan91c11x_read_reg(LAN91C11X_MGMT) & 0xfff0);
144
145    /* Clock all 64 cycles */
146    for (i = 0; i < sizeof bits; ++i) {
147        /* Clock Low - output data */
148        lan91c11x_write_reg(LAN91C11X_MGMT, bits[i]);
149        rtems_task_wake_after(1);
150
151        /* Clock Hi - input data */
152        lan91c11x_write_reg(LAN91C11X_MGMT, bits[i] | LAN91C11X_MGMT_MCLK);
153        rtems_task_wake_after(1);
154        bits[i] |= lan91c11x_read_reg(LAN91C11X_MGMT) & LAN91C11X_MGMT_MDI;
155    }
156
157    /* Return to idle state */
158    /* Set clock to low, data to low, and output tristated */
159    lan91c11x_write_reg(LAN91C11X_MGMT, lan91c11x_read_reg(LAN91C11X_MGMT) & 0xfff0);
160    rtems_task_wake_after(1);
161
162    /* Recover input data */
163    phydata = 0;
164    for (i = 0; i < 16; ++i) {
165        phydata <<= 1;
166
167        if (bits[input_idx++] & LAN91C11X_MGMT_MDI) {
168            phydata |= 0x0001;
169        }
170    }
171
172    return phydata;
173}
174
175
176
177void lan91c11x_write_phy_reg(int reg, uint16_t phydata)
178{
179    int i;
180    ushort mask;
181    ushort bits[64];
182    int clk_idx = 0;
183
184    /* 32 consecutive ones on MDO to establish sync */
185    for (i = 0; i < 32; ++i) {
186        bits[clk_idx++] = LAN91C11X_MGMT_MDOE | LAN91C11X_MGMT_MDO;
187    }
188
189    /* Start code <01> */
190    bits[clk_idx++] = LAN91C11X_MGMT_MDOE;
191    bits[clk_idx++] = LAN91C11X_MGMT_MDOE | LAN91C11X_MGMT_MDO;
192
193    /* Write command <01> */
194    bits[clk_idx++] = LAN91C11X_MGMT_MDOE;
195    bits[clk_idx++] = LAN91C11X_MGMT_MDOE | LAN91C11X_MGMT_MDO;
196
197    /* Output the PHY address, msb first - Internal PHY is address 0 */
198    for (i = 0; i < 5; ++i) {
199        bits[clk_idx++] = LAN91C11X_MGMT_MDOE;
200    }
201
202    /* Output the phy register number, msb first */
203    mask = 0x10;
204    for (i = 0; i < 5; ++i) {
205        if (reg & mask) {
206            bits[clk_idx++] = LAN91C11X_MGMT_MDOE | LAN91C11X_MGMT_MDO;
207        } else {
208            bits[clk_idx++] = LAN91C11X_MGMT_MDOE;
209        }
210
211        /* Shift to next lowest bit */
212        mask >>= 1;
213    }
214
215    /* 2 extra bit times for turnaround */
216    bits[clk_idx++] = 0;
217    bits[clk_idx++] = 0;
218
219    /* Write out 16 bits of data, msb first */
220    mask = 0x8000;
221    for (i = 0; i < 16; ++i) {
222        if (phydata & mask) {
223            bits[clk_idx++] = LAN91C11X_MGMT_MDOE | LAN91C11X_MGMT_MDO;
224        } else {
225            bits[clk_idx++] = LAN91C11X_MGMT_MDOE;
226        }
227
228        /* Shift to next lowest bit */
229        mask >>= 1;
230    }
231
232    /* Turn off all MII Interface bits */
233    lan91c11x_write_reg(LAN91C11X_MGMT,
234                        lan91c11x_read_reg(LAN91C11X_MGMT) & 0xfff0);
235
236    /* Clock all 64 cycles */
237    for (i = 0; i < sizeof bits; ++i) {
238        /* Clock Low - output data */
239        lan91c11x_write_reg(LAN91C11X_MGMT, bits[i]);
240        rtems_task_wake_after(1);
241
242        /* Clock Hi - input data */
243        lan91c11x_write_reg(LAN91C11X_MGMT, bits[i] | LAN91C11X_MGMT_MCLK);
244        rtems_task_wake_after(1);
245        bits[i] |= lan91c11x_read_reg(LAN91C11X_MGMT) & LAN91C11X_MGMT_MDI;
246    }
247
248    /* Return to idle state */
249    /* Set clock to low, data to low, and output tristated */
250    lan91c11x_write_reg(LAN91C11X_MGMT,
251                        lan91c11x_read_reg(LAN91C11X_MGMT) & 0xfff0);
252    rtems_task_wake_after(1);
253
254}
255
256
257
Note: See TracBrowser for help on using the repository browser.