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

4.8
Last change on this file since e02d489a was e02d489a, checked in by Joel Sherrill <joel.sherrill@…>, on Jan 6, 2009 at 4:26:55 PM

2009-01-06 Joel Sherrill <joel.sherrill@…>

PR 1350/bsps

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