Skip to content
GitLab
Projects
Groups
Snippets
Help
Loading...
Help
What's new
7
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Sign in / Register
Toggle navigation
Open sidebar
Librem5
uboot-imx
Commits
0a16ea59
Commit
0a16ea59
authored
Nov 26, 2012
by
Albert ARIBAUD
Committed by
Prafulla Wadaskar
Jan 09, 2013
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
mv88e61xx: refactor PHY and SWITCH level-code
Signed-off-by:
Albert ARIBAUD
<
albert.u.boot@aribaud.net
>
parent
136846d7
Changes
3
Hide whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
358 additions
and
197 deletions
+358
-197
drivers/net/phy/mv88e61xx.c
drivers/net/phy/mv88e61xx.c
+315
-180
drivers/net/phy/mv88e61xx.h
drivers/net/phy/mv88e61xx.h
+27
-12
include/netdev.h
include/netdev.h
+16
-5
No files found.
drivers/net/phy/mv88e61xx.c
View file @
0a16ea59
...
@@ -26,6 +26,14 @@
...
@@ -26,6 +26,14 @@
#include <netdev.h>
#include <netdev.h>
#include "mv88e61xx.h"
#include "mv88e61xx.h"
/*
* Uncomment either of the following line for local debug control;
* otherwise global debug control will apply.
*/
/* #undef DEBUG */
/* #define DEBUG */
#ifdef CONFIG_MV88E61XX_MULTICHIP_ADRMODE
#ifdef CONFIG_MV88E61XX_MULTICHIP_ADRMODE
/* Chip Address mode
/* Chip Address mode
* The Switch support two modes of operation
* The Switch support two modes of operation
...
@@ -52,7 +60,8 @@ static int mv88e61xx_busychk_multic(char *name, u32 devaddr)
...
@@ -52,7 +60,8 @@ static int mv88e61xx_busychk_multic(char *name, u32 devaddr)
return
0
;
return
0
;
}
}
static
void
mv88e61xx_wr_phy
(
char
*
name
,
u32
phy_adr
,
u32
reg_ofs
,
u16
data
)
static
void
mv88e61xx_switch_write
(
char
*
name
,
u32
phy_adr
,
u32
reg_ofs
,
u16
data
)
{
{
u16
mii_dev_addr
;
u16
mii_dev_addr
;
...
@@ -70,7 +79,8 @@ static void mv88e61xx_wr_phy(char *name, u32 phy_adr, u32 reg_ofs, u16 data)
...
@@ -70,7 +79,8 @@ static void mv88e61xx_wr_phy(char *name, u32 phy_adr, u32 reg_ofs, u16 data)
15
));
15
));
}
}
static
void
mv88e61xx_rd_phy
(
char
*
name
,
u32
phy_adr
,
u32
reg_ofs
,
u16
*
data
)
static
void
mv88e61xx_switch_read
(
char
*
name
,
u32
phy_adr
,
u32
reg_ofs
,
u16
*
data
)
{
{
u16
mii_dev_addr
;
u16
mii_dev_addr
;
...
@@ -90,110 +100,51 @@ static void mv88e61xx_rd_phy(char *name, u32 phy_adr, u32 reg_ofs, u16 * data)
...
@@ -90,110 +100,51 @@ static void mv88e61xx_rd_phy(char *name, u32 phy_adr, u32 reg_ofs, u16 * data)
}
}
#endif
/* CONFIG_MV88E61XX_MULTICHIP_ADRMODE */
#endif
/* CONFIG_MV88E61XX_MULTICHIP_ADRMODE */
static
void
mv88e61xx_port_vlan_config
(
struct
mv88e61xx_config
*
swconfig
,
/*
u32
max_prtnum
,
u32
ports_ofs
)
* Convenience macros for switch device/port reads/writes
{
* These macros output valid 'mv88e61xx' U_BOOT_CMDs
u32
prt
;
*/
u16
reg
;
char
*
name
=
swconfig
->
name
;
u32
cpu_port
=
swconfig
->
cpuport
;
u32
port_mask
=
swconfig
->
ports_enabled
;
enum
mv88e61xx_cfg_vlan
vlancfg
=
swconfig
->
vlancfg
;
/* be sure all ports are disabled */
for
(
prt
=
0
;
prt
<
max_prtnum
;
prt
++
)
{
RD_PHY
(
name
,
ports_ofs
+
prt
,
MV88E61XX_PRT_CTRL_REG
,
&
reg
);
reg
&=
~
0x3
;
WR_PHY
(
name
,
ports_ofs
+
prt
,
MV88E61XX_PRT_CTRL_REG
,
reg
);
if
(
!
(
cpu_port
&
(
1
<<
prt
)))
continue
;
/* Set CPU port VID to 0x1 */
RD_PHY
(
name
,
(
ports_ofs
+
prt
),
MV88E61XX_PRT_VID_REG
,
&
reg
);
reg
&=
~
0xfff
;
reg
|=
0x1
;
WR_PHY
(
name
,
(
ports_ofs
+
prt
),
MV88E61XX_PRT_VID_REG
,
reg
);
}
/* Setting Port default priority for all ports to zero */
for
(
prt
=
0
;
prt
<
max_prtnum
;
prt
++
)
{
RD_PHY
(
name
,
ports_ofs
+
prt
,
MV88E61XX_PRT_VID_REG
,
&
reg
);
reg
&=
~
0xc000
;
WR_PHY
(
name
,
ports_ofs
+
prt
,
MV88E61XX_PRT_VID_REG
,
reg
);
}
/* Setting VID and VID map for all ports except CPU port */
for
(
prt
=
0
;
prt
<
max_prtnum
;
prt
++
)
{
/* only for enabled ports */
if
((
1
<<
prt
)
&
port_mask
)
{
/* skip CPU port */
if
((
1
<<
prt
)
&
cpu_port
)
{
/*
* Set Vlan map table for cpu_port to see
* all ports
*/
RD_PHY
(
name
,
(
ports_ofs
+
prt
),
MV88E61XX_PRT_VMAP_REG
,
&
reg
);
reg
&=
~
((
1
<<
max_prtnum
)
-
1
);
reg
|=
port_mask
&
~
(
1
<<
prt
);
WR_PHY
(
name
,
(
ports_ofs
+
prt
),
MV88E61XX_PRT_VMAP_REG
,
reg
);
}
else
{
/*
* set Ports VLAN Mapping.
* port prt <--> cpu_port VLAN #prt+1.
*/
RD_PHY
(
name
,
ports_ofs
+
prt
,
MV88E61XX_PRT_VID_REG
,
&
reg
);
reg
&=
~
0x0fff
;
reg
|=
(
prt
+
1
);
WR_PHY
(
name
,
ports_ofs
+
prt
,
MV88E61XX_PRT_VID_REG
,
reg
);
RD_PHY
(
name
,
ports_ofs
+
prt
,
MV88E61XX_PRT_VMAP_REG
,
&
reg
);
if
(
vlancfg
==
MV88E61XX_VLANCFG_DEFAULT
)
{
/*
* all any port can send frames to all other ports
* ref: sec 3.2.1.1 of datasheet
*/
reg
|=
0x03f
;
reg
&=
~
(
1
<<
prt
);
}
else
if
(
vlancfg
==
MV88E61XX_VLANCFG_ROUTER
)
{
/*
* all other ports can send frames to CPU port only
* ref: sec 3.2.1.2 of datasheet
*/
reg
&=
~
((
1
<<
max_prtnum
)
-
1
);
reg
|=
cpu_port
;
}
WR_PHY
(
name
,
ports_ofs
+
prt
,
MV88E61XX_PRT_VMAP_REG
,
reg
);
}
}
}
/*
#ifndef DEBUG
* enable only appropriate ports to forwarding mode
#define WR_SWITCH_REG wr_switch_reg
* and disable the others
#define RD_SWITCH_REG rd_switch_reg
*/
#define WR_SWITCH_PORT_REG(n, p, r, d) \
for
(
prt
=
0
;
prt
<
max_prtnum
;
prt
++
)
{
WR_SWITCH_REG(n, (MV88E61XX_PRT_OFST+p), r, d)
if
((
1
<<
prt
)
&
port_mask
)
{
#define RD_SWITCH_PORT_REG(n, p, r, d) \
RD_PHY
(
name
,
ports_ofs
+
prt
,
RD_SWITCH_REG(n, (MV88E61XX_PRT_OFST+p), r, d)
MV88E61XX_PRT_CTRL_REG
,
&
reg
);
#else
reg
|=
0x3
;
static
void
WR_SWITCH_REG
(
char
*
name
,
u32
dev_adr
,
u32
reg_ofs
,
u16
data
)
WR_PHY
(
name
,
ports_ofs
+
prt
,
{
MV88E61XX_PRT_CTRL_REG
,
reg
);
printf
(
"mv88e61xx %s dev %02x reg %02x write %04x
\n
"
,
}
else
{
name
,
dev_adr
,
reg_ofs
,
data
);
/* Disable port */
wr_switch_reg
(
name
,
dev_adr
,
reg_ofs
,
data
);
RD_PHY
(
name
,
ports_ofs
+
prt
,
MV88E61XX_PRT_CTRL_REG
,
&
reg
);
reg
&=
~
0x3
;
WR_PHY
(
name
,
ports_ofs
+
prt
,
MV88E61XX_PRT_CTRL_REG
,
reg
);
}
}
}
}
static
void
RD_SWITCH_REG
(
char
*
name
,
u32
dev_adr
,
u32
reg_ofs
,
u16
*
data
)
{
rd_switch_reg
(
name
,
dev_adr
,
reg_ofs
,
data
);
printf
(
"mv88e61xx %s dev %02x reg %02x read %04x
\n
"
,
name
,
dev_adr
,
reg_ofs
,
*
data
);
}
static
void
WR_SWITCH_PORT_REG
(
char
*
name
,
u32
prt_adr
,
u32
reg_ofs
,
u16
data
)
{
printf
(
"mv88e61xx %s port %02x reg %02x write %04x
\n
"
,
name
,
prt_adr
,
reg_ofs
,
data
);
wr_switch_reg
(
name
,
(
MV88E61XX_PRT_OFST
+
prt_adr
),
reg_ofs
,
data
);
}
static
void
RD_SWITCH_PORT_REG
(
char
*
name
,
u32
prt_adr
,
u32
reg_ofs
,
u16
*
data
)
{
rd_switch_reg
(
name
,
(
MV88E61XX_PRT_OFST
+
prt_adr
),
reg_ofs
,
data
);
printf
(
"mv88e61xx %s port %02x reg %02x read %04x
\n
"
,
name
,
prt_adr
,
reg_ofs
,
*
data
);
}
#endif
/*
* Local functions to read/write registers on the switch PHYs.
* NOTE! This goes through switch, not direct miiphy, writes and reads!
*/
/*
/*
* Make sure SMIBusy bit cleared before another
* Make sure SMIBusy bit cleared before another
...
@@ -204,7 +155,7 @@ static int mv88e61xx_busychk(char *name)
...
@@ -204,7 +155,7 @@ static int mv88e61xx_busychk(char *name)
u16
reg
=
0
;
u16
reg
=
0
;
u32
timeout
=
MV88E61XX_PHY_TIMEOUT
;
u32
timeout
=
MV88E61XX_PHY_TIMEOUT
;
do
{
do
{
RD_PHY
(
name
,
MV88E61XX_GLB2REG_DEVADR
,
rd_switch_reg
(
name
,
MV88E61XX_GLB2REG_DEVADR
,
MV88E61XX_PHY_CMD
,
&
reg
);
MV88E61XX_PHY_CMD
,
&
reg
);
if
(
timeout
--
==
0
)
{
if
(
timeout
--
==
0
)
{
printf
(
"SMI busy timeout
\n
"
);
printf
(
"SMI busy timeout
\n
"
);
...
@@ -214,34 +165,110 @@ static int mv88e61xx_busychk(char *name)
...
@@ -214,34 +165,110 @@ static int mv88e61xx_busychk(char *name)
return
0
;
return
0
;
}
}
static
inline
int
mv88e61xx_switch_miiphy_write
(
char
*
name
,
u32
phy
,
u32
reg
,
u16
data
)
{
/* write switch data reg then cmd reg then check completion */
wr_switch_reg
(
name
,
MV88E61XX_GLB2REG_DEVADR
,
MV88E61XX_PHY_DATA
,
data
);
wr_switch_reg
(
name
,
MV88E61XX_GLB2REG_DEVADR
,
MV88E61XX_PHY_CMD
,
(
MV88E61XX_PHY_WRITE_CMD
|
(
phy
<<
5
)
|
reg
));
return
mv88e61xx_busychk
(
name
);
}
static
inline
int
mv88e61xx_switch_miiphy_read
(
char
*
name
,
u32
phy
,
u32
reg
,
u16
*
data
)
{
/* write switch cmd reg, check for completion */
wr_switch_reg
(
name
,
MV88E61XX_GLB2REG_DEVADR
,
MV88E61XX_PHY_CMD
,
(
MV88E61XX_PHY_READ_CMD
|
(
phy
<<
5
)
|
reg
));
if
(
mv88e61xx_busychk
(
name
))
return
-
1
;
/* read switch data reg and return success */
rd_switch_reg
(
name
,
MV88E61XX_GLB2REG_DEVADR
,
MV88E61XX_PHY_DATA
,
data
);
return
0
;
}
/*
* Convenience macros for switch PHY reads/writes
*/
#ifndef DEBUG
#define WR_SWITCH_PHY_REG mv88e61xx_switch_miiphy_write
#define RD_SWITCH_PHY_REG mv88e61xx_switch_miiphy_read
#else
static
inline
int
WR_SWITCH_PHY_REG
(
char
*
name
,
u32
phy_adr
,
u32
reg_ofs
,
u16
data
)
{
int
r
=
mv88e61xx_switch_miiphy_write
(
name
,
phy_adr
,
reg_ofs
,
data
);
if
(
r
)
printf
(
"** ERROR writing mv88e61xx %s phy %02x reg %02x
\n
"
,
name
,
phy_adr
,
reg_ofs
);
else
printf
(
"mv88e61xx %s phy %02x reg %02x write %04x
\n
"
,
name
,
phy_adr
,
reg_ofs
,
data
);
return
r
;
}
static
inline
int
RD_SWITCH_PHY_REG
(
char
*
name
,
u32
phy_adr
,
u32
reg_ofs
,
u16
*
data
)
{
int
r
=
mv88e61xx_switch_miiphy_read
(
name
,
phy_adr
,
reg_ofs
,
data
);
if
(
r
)
printf
(
"** ERROR reading mv88e61xx %s phy %02x reg %02x
\n
"
,
name
,
phy_adr
,
reg_ofs
);
else
printf
(
"mv88e61xx %s phy %02x reg %02x read %04x
\n
"
,
name
,
phy_adr
,
reg_ofs
,
*
data
);
return
r
;
}
#endif
static
void
mv88e61xx_port_vlan_config
(
struct
mv88e61xx_config
*
swconfig
)
{
u32
prt
;
u16
reg
;
char
*
name
=
swconfig
->
name
;
u32
port_mask
=
swconfig
->
ports_enabled
;
/* apply internal vlan config */
for
(
prt
=
0
;
prt
<
MV88E61XX_MAX_PORTS_NUM
;
prt
++
)
{
/* only for enabled ports */
if
((
1
<<
prt
)
&
port_mask
)
{
/* take vlan map from swconfig */
u8
vlanmap
=
swconfig
->
vlancfg
[
prt
];
/* remove disabled ports from vlan map */
vlanmap
&=
swconfig
->
ports_enabled
;
/* apply vlan map to port */
RD_SWITCH_PORT_REG
(
name
,
prt
,
MV88E61XX_PRT_VMAP_REG
,
&
reg
);
reg
&=
~
((
1
<<
MV88E61XX_MAX_PORTS_NUM
)
-
1
);
reg
|=
vlanmap
;
WR_SWITCH_PORT_REG
(
name
,
prt
,
MV88E61XX_PRT_VMAP_REG
,
reg
);
}
}
}
/*
/*
* Power up the specified port and reset PHY
* Power up the specified port and reset PHY
*/
*/
static
int
mv88361xx_powerup
(
struct
mv88e61xx_config
*
swconfig
,
u32
p
rt
)
static
int
mv88361xx_powerup
(
struct
mv88e61xx_config
*
swconfig
,
u32
p
hy
)
{
{
char
*
name
=
swconfig
->
name
;
char
*
name
=
swconfig
->
name
;
/* Write Copper Specific control reg1 (0x1
4
) for-
/* Write Copper Specific control reg1 (0x1
0
) for-
* Enable Phy power up
* Enable Phy power up
* Energy Detect on (sense&Xmit NLP Periodically
* Energy Detect on (sense&Xmit NLP Periodically
* reset other settings default
* reset other settings default
*/
*/
WR_PHY
(
name
,
MV88E61XX_GLB2REG_DEVADR
,
MV88E61XX_PHY_DATA
,
0x3360
);
if
(
WR_SWITCH_PHY_REG
(
name
,
phy
,
0x10
,
0x3360
))
WR_PHY
(
name
,
MV88E61XX_GLB2REG_DEVADR
,
MV88E61XX_PHY_CMD
,
(
0x9410
|
(
prt
<<
5
)));
if
(
mv88e61xx_busychk
(
name
))
return
-
1
;
return
-
1
;
/* Write PHY ctrl reg (0x0) to apply
/* Write PHY ctrl reg (0x0) to apply
* Phy reset (set bit 15 low)
* Phy reset (set bit 15 low)
* reset other default values
* reset other default values
*/
*/
WR_PHY
(
name
,
MV88E61XX_GLB2REG_DEVADR
,
MV88E61XX_PHY_DATA
,
0x1140
);
if
(
WR_SWITCH_PHY_REG
(
name
,
phy
,
0x00
,
0x9140
))
WR_PHY
(
name
,
MV88E61XX_GLB2REG_DEVADR
,
MV88E61XX_PHY_CMD
,
(
0x9400
|
(
prt
<<
5
)));
if
(
mv88e61xx_busychk
(
name
))
return
-
1
;
return
-
1
;
return
0
;
return
0
;
...
@@ -256,48 +283,26 @@ static int mv88361xx_powerup(struct mv88e61xx_config *swconfig, u32 prt)
...
@@ -256,48 +283,26 @@ static int mv88361xx_powerup(struct mv88e61xx_config *swconfig, u32 prt)
* to setup PHY LEDs default configuration to detect 10/100/1000Mb/s
* to setup PHY LEDs default configuration to detect 10/100/1000Mb/s
* Link status
* Link status
*/
*/
static
int
mv88361xx_led_init
(
struct
mv88e61xx_config
*
swconfig
,
u32
p
rt
)
static
int
mv88361xx_led_init
(
struct
mv88e61xx_config
*
swconfig
,
u32
p
hy
)
{
{
char
*
name
=
swconfig
->
name
;
char
*
name
=
swconfig
->
name
;
u16
reg
;
if
(
swconfig
->
led_init
!=
MV88E61XX_LED_INIT_EN
)
if
(
swconfig
->
led_init
!=
MV88E61XX_LED_INIT_EN
)
return
0
;
return
0
;
/* set page address to 3 */
/* set page address to 3 */
reg
=
3
;
if
(
WR_SWITCH_PHY_REG
(
name
,
phy
,
0x16
,
0x0003
))
WR_PHY
(
name
,
MV88E61XX_GLB2REG_DEVADR
,
MV88E61XX_PHY_DATA
,
reg
);
WR_PHY
(
name
,
MV88E61XX_GLB2REG_DEVADR
,
MV88E61XX_PHY_CMD
,
(
1
<<
MV88E61XX_BUSY_OFST
|
1
<<
MV88E61XX_MODE_OFST
|
1
<<
MV88E61XX_OP_OFST
|
prt
<<
MV88E61XX_ADDR_OFST
|
22
));
if
(
mv88e61xx_busychk
(
name
))
return
-
1
;
return
-
1
;
/* set LED Func Ctrl reg */
/*
reg
=
1
;
/* LED[0] On-Link, Blink-Activity, Off-NoLink */
* set LED Func Ctrl reg
WR_PHY
(
name
,
MV88E61XX_GLB2REG_DEVADR
,
MV88E61XX_PHY_DATA
,
reg
);
* value 0x0001 = LED[0] On-Link, Blink-Activity, Off-NoLink
WR_PHY
(
name
,
MV88E61XX_GLB2REG_DEVADR
,
*/
MV88E61XX_PHY_CMD
,
(
1
<<
MV88E61XX_BUSY_OFST
|
if
(
WR_SWITCH_PHY_REG
(
name
,
phy
,
0x10
,
0x0001
))
1
<<
MV88E61XX_MODE_OFST
|
1
<<
MV88E61XX_OP_OFST
|
prt
<<
MV88E61XX_ADDR_OFST
|
16
));
if
(
mv88e61xx_busychk
(
name
))
return
-
1
;
return
-
1
;
/* set page address to 0 */
/* set page address to 0 */
reg
=
0
;
if
(
WR_SWITCH_PHY_REG
(
name
,
phy
,
0x16
,
0x0000
))
WR_PHY
(
name
,
MV88E61XX_GLB2REG_DEVADR
,
MV88E61XX_PHY_DATA
,
reg
);
WR_PHY
(
name
,
MV88E61XX_GLB2REG_DEVADR
,
MV88E61XX_PHY_CMD
,
(
1
<<
MV88E61XX_BUSY_OFST
|
1
<<
MV88E61XX_MODE_OFST
|
1
<<
MV88E61XX_OP_OFST
|
prt
<<
MV88E61XX_ADDR_OFST
|
22
));
if
(
mv88e61xx_busychk
(
name
))
return
-
1
;
return
-
1
;
return
0
;
return
0
;
...
@@ -312,23 +317,15 @@ static int mv88361xx_led_init(struct mv88e61xx_config *swconfig, u32 prt)
...
@@ -312,23 +317,15 @@ static int mv88361xx_led_init(struct mv88e61xx_config *swconfig, u32 prt)
* This is optional settings may be needed on some boards
* This is optional settings may be needed on some boards
* for PHY<->magnetics h/w tuning
* for PHY<->magnetics h/w tuning
*/
*/
static
int
mv88361xx_reverse_mdipn
(
struct
mv88e61xx_config
*
swconfig
,
u32
p
rt
)
static
int
mv88361xx_reverse_mdipn
(
struct
mv88e61xx_config
*
swconfig
,
u32
p
hy
)
{
{
char
*
name
=
swconfig
->
name
;
char
*
name
=
swconfig
->
name
;
u16
reg
;
if
(
swconfig
->
mdip
!=
MV88E61XX_MDIP_REVERSE
)
if
(
swconfig
->
mdip
!=
MV88E61XX_MDIP_REVERSE
)
return
0
;
return
0
;
reg
=
0x0f
;
/*Reverse MDIP/N[3:0] bits */
/*Reverse MDIP/N[3:0] bits */
WR_PHY
(
name
,
MV88E61XX_GLB2REG_DEVADR
,
MV88E61XX_PHY_DATA
,
reg
);
if
(
WR_SWITCH_PHY_REG
(
name
,
phy
,
0x14
,
0x000f
))
WR_PHY
(
name
,
MV88E61XX_GLB2REG_DEVADR
,
MV88E61XX_PHY_CMD
,
(
1
<<
MV88E61XX_BUSY_OFST
|
1
<<
MV88E61XX_MODE_OFST
|
1
<<
MV88E61XX_OP_OFST
|
prt
<<
MV88E61XX_ADDR_OFST
|
20
));
if
(
mv88e61xx_busychk
(
name
))
return
-
1
;
return
-
1
;
return
0
;
return
0
;
...
@@ -343,6 +340,7 @@ int mv88e61xx_switch_initialize(struct mv88e61xx_config *swconfig)
...
@@ -343,6 +340,7 @@ int mv88e61xx_switch_initialize(struct mv88e61xx_config *swconfig)
u16
reg
;
u16
reg
;
char
*
idstr
;
char
*
idstr
;
char
*
name
=
swconfig
->
name
;
char
*
name
=
swconfig
->
name
;
int
time
;
if
(
miiphy_set_current_dev
(
name
))
{
if
(
miiphy_set_current_dev
(
name
))
{
printf
(
"%s failed
\n
"
,
__FUNCTION__
);
printf
(
"%s failed
\n
"
,
__FUNCTION__
);
...
@@ -354,7 +352,7 @@ int mv88e61xx_switch_initialize(struct mv88e61xx_config *swconfig)
...
@@ -354,7 +352,7 @@ int mv88e61xx_switch_initialize(struct mv88e61xx_config *swconfig)
printf
(
"Invalid cpu port config, using default port5
\n
"
);
printf
(
"Invalid cpu port config, using default port5
\n
"
);
}
}
RD_
PHY
(
name
,
MV88E61XX_PRT_OFST
,
MII_PHYSID2
,
&
reg
);
RD_
SWITCH_PORT_REG
(
name
,
0
,
MII_PHYSID2
,
&
reg
);
switch
(
reg
&=
0xfff0
)
{
switch
(
reg
&=
0xfff0
)
{
case
0x1610
:
case
0x1610
:
idstr
=
"88E6161"
;
idstr
=
"88E6161"
;
...
@@ -373,46 +371,183 @@ int mv88e61xx_switch_initialize(struct mv88e61xx_config *swconfig)
...
@@ -373,46 +371,183 @@ int mv88e61xx_switch_initialize(struct mv88e61xx_config *swconfig)
break
;
break
;
}
}
/* Port based VLANs configuration */
/* be sure all ports are disabled */
if
((
swconfig
->
vlancfg
==
MV88E61XX_VLANCFG_DEFAULT
)
for
(
prt
=
0
;
prt
<
MV88E61XX_MAX_PORTS_NUM
;
prt
++
)
{
||
(
swconfig
->
vlancfg
==
MV88E61XX_VLANCFG_ROUTER
))
RD_SWITCH_PORT_REG
(
name
,
prt
,
MV88E61XX_PRT_CTRL_REG
,
&
reg
);
mv88e61xx_port_vlan_config
(
swconfig
,
MV88E61XX_MAX_PORTS_NUM
,
reg
&=
~
0x3
;
MV88E61XX_PRT_OFST
);
WR_SWITCH_PORT_REG
(
name
,
prt
,
MV88E61XX_PRT_CTRL_REG
,
reg
);
else
{
printf
(
"Unsupported mode %s failed
\n
"
,
__FUNCTION__
);
return
-
1
;
}
}
/* wait 2 ms for queues to drain */
udelay
(
2000
);
/* reset switch */
RD_SWITCH_REG
(
name
,
MV88E61XX_GLBREG_DEVADR
,
MV88E61XX_SGCR
,
&
reg
);
reg
|=
0x8000
;
WR_SWITCH_REG
(
name
,
MV88E61XX_GLBREG_DEVADR
,
MV88E61XX_SGCR
,
reg
);
/* wait up to 1 second for switch reset complete */
for
(
time
=
1000
;
time
;
time
--
)
{
RD_SWITCH_REG
(
name
,
MV88E61XX_GLBREG_DEVADR
,
MV88E61XX_SGSR
,
&
reg
);
if
((
reg
&
0xc800
)
==
0xc800
)
break
;
udelay
(
1000
);
}
if
(
!
time
)
return
-
1
;
/* Port based VLANs configuration */
mv88e61xx_port_vlan_config
(
swconfig
);
if
(
swconfig
->
rgmii_delay
==
MV88E61XX_RGMII_DELAY_EN
)
{
if
(
swconfig
->
rgmii_delay
==
MV88E61XX_RGMII_DELAY_EN
)
{
/*
/*
* Enable RGMII delay on Tx and Rx for CPU port
* Enable RGMII delay on Tx and Rx for CPU port
* Ref: sec 9.5 of chip datasheet-02
* Ref: sec 9.5 of chip datasheet-02
*/
*/
WR_PHY
(
name
,
MV88E61XX_PRT_OFST
+
5
,
/*Force port link down */
MV88E61XX_RGMII_TIMECTRL_REG
,
0x18
);
WR_SWITCH_PORT_REG
(
name
,
5
,
MV88E61XX_PCS_CTRL_REG
,
0x10
);
WR_PHY
(
name
,
MV88E61XX_PRT_OFST
+
4
,
/* configure port RGMII delay */
MV88E61XX_RGMII_TIMECTRL_REG
,
0xc1e7
);
WR_SWITCH_PORT_REG
(
name
,
4
,
MV88E61XX_RGMII_TIMECTRL_REG
,
0x81e7
);
RD_SWITCH_PORT_REG
(
name
,
5
,
MV88E61XX_RGMII_TIMECTRL_REG
,
&
reg
);
WR_SWITCH_PORT_REG
(
name
,
5
,
MV88E61XX_RGMII_TIMECTRL_REG
,
reg
|
0x18
);
WR_SWITCH_PORT_REG
(
name
,
4
,
MV88E61XX_RGMII_TIMECTRL_REG
,
0xc1e7
);
/* Force port to RGMII FDX 1000Base then up */
WR_SWITCH_PORT_REG
(
name
,
5
,
MV88E61XX_PCS_CTRL_REG
,
0x1e
);
WR_SWITCH_PORT_REG
(
name
,
5
,
MV88E61XX_PCS_CTRL_REG
,
0x3e
);
}
}
for
(
prt
=
0
;
prt
<
MV88E61XX_MAX_PORTS_NUM
;
prt
++
)
{
for
(
prt
=
0
;
prt
<
MV88E61XX_MAX_PORTS_NUM
;
prt
++
)
{
if
(
!
((
1
<<
prt
)
&
swconfig
->
cpuport
))
{
if
(
mv88361xx_led_init
(
swconfig
,
prt
))
/* configure port's PHY */
if
(
!
((
1
<<
prt
)
&
swconfig
->
cpuport
))
{
/* port 4 has phy 6, not 4 */
int
phy
=
(
prt
==
4
)
?
6
:
prt
;
if
(
mv88361xx_powerup
(
swconfig
,
phy
))
return
-
1
;
return
-
1
;
if
(
mv88361xx_reverse_mdipn
(
swconfig
,
p
rt
))
if
(
mv88361xx_reverse_mdipn
(
swconfig
,
p
hy
))
return
-
1
;
return
-
1
;
if
(
mv88361xx_
powerup
(
swconfig
,
p
rt
))
if
(
mv88361xx_
led_init
(
swconfig
,
p
hy
))
return
-
1
;
return
-
1
;
}
}
/* set port VID to port+1 except for cpu port */
if
(
!
((
1
<<
prt
)
&
swconfig
->
cpuport
))
{
RD_SWITCH_PORT_REG
(
name
,
prt
,
MV88E61XX_PRT_VID_REG
,
&
reg
);
WR_SWITCH_PORT_REG
(
name
,
prt
,
MV88E61XX_PRT_VID_REG
,
(
reg
&
~
1023
)
|
(
prt
+
1
));
}
/*Program port state */
/*Program port state */
RD_PHY
(
name
,
MV88E61XX_PRT_OFST
+
prt
,
RD_SWITCH_PORT_REG
(
name
,
prt
,
MV88E61XX_PRT_CTRL_REG
,
&
reg
);
MV88E61XX_PRT_CTRL_REG
,
&
reg
);
WR_PHY
(
name
,
MV88E61XX_PRT_OFST
+
prt
,
WR_SWITCH_PORT_REG
(
name
,
prt
,
MV88E61XX_PRT_CTRL_REG
,
MV88E61XX_PRT_CTRL_REG
,
reg
|
(
swconfig
->
portstate
&
0x03
));
reg
|
(
swconfig
->
portstate
&
0x03
));
}
}
printf
(
"%s Initialized on %s
\n
"
,
idstr
,
name
);
printf
(
"%s Initialized on %s
\n
"
,
idstr
,
name
);
return
0
;
return
0
;
}
}
#ifdef CONFIG_MV88E61XX_CMD
static
int
do_switch
(
cmd_tbl_t
*
cmdtp
,
int
flag
,
int
argc
,
char
*
const
argv
[])
{
char
*
name
,
*
endp
;
int
write
=
0
;
enum
{
dev
,
prt
,
phy
}
target
=
dev
;
u32
addrlo
,
addrhi
,
addr
;
u32
reglo
,
reghi
,
reg
;
u16
data
,
rdata
;