1
0
mirror of git://projects.qi-hardware.com/openwrt-xburst.git synced 2024-11-17 08:37:09 +02:00

ip17xx: Add support for IP175D

Add support for the IP175D chip. Since the register set is vastly different
from the previous models, we cannot not use the register number tables in struct
register_mappings (except for VLAN_DEFAULT_TAG_REG), so we supply a different
set of low-level functions.

Unlike with the previous models, we keep the VLAN setup in our state structure
instead of querying the hardware (it would be much harder in case of IP175D,
because the mapping between hardware and software state is not 1:1). Therefore,
get_flags() and get_state() are no-ops.

Signed-off-by: Martin Mares <mj@ucw.cz>
Signed-off-by: Patrick Horn <patrick.horn@gmail.com>


git-svn-id: svn://svn.openwrt.org/openwrt/trunk@21721 3c298f89-4303-0410-b956-a3cf2f4a3e73
This commit is contained in:
juhosg 2010-06-08 20:18:51 +00:00
parent 714e378fed
commit b105730015

View File

@ -263,6 +263,56 @@ static const struct register_mappings IP175A = {
};
static int ip175d_get_flags(struct ip175c_state *state);
static int ip175d_get_state(struct ip175c_state *state);
static int ip175d_update_state(struct ip175c_state *state);
static int ip175d_set_vlan_mode(struct ip175c_state *state);
static int ip175d_reset(struct ip175c_state *state);
static const struct register_mappings IP175D = {
.NAME = "IP175D",
.MODEL_NO = 0x18,
// The IP175D has a completely different interface, so we leave most
// of the registers undefined and switch to different code paths.
.VLAN_DEFAULT_TAG_REG = {
NOTSUPPORTED,NOTSUPPORTED,NOTSUPPORTED,NOTSUPPORTED,
NOTSUPPORTED,NOTSUPPORTED,NOTSUPPORTED,NOTSUPPORTED,
},
.ADD_TAG_REG = NOTSUPPORTED,
.REMOVE_TAG_REG = NOTSUPPORTED,
.SIMPLE_VLAN_REGISTERS = 0,
.VLAN_LOOKUP_REG = NOTSUPPORTED,
.VLAN_LOOKUP_REG_5 = NOTSUPPORTED,
.TAG_VLAN_MASK_REG = NOTSUPPORTED,
.RESET_VAL = 0x175D,
.RESET_REG = {20,2},
.MODE_REG = NOTSUPPORTED,
.ROUTER_CONTROL_REG = NOTSUPPORTED,
.ROUTER_EN_BIT = -1,
.NUMLAN_GROUPS_BIT = -1,
.VLAN_CONTROL_REG = NOTSUPPORTED,
.TAG_VLAN_BIT = -1,
.NUM_PORTS = 6,
.CPU_PORT = 5,
.MII_REGISTER_EN = NOTSUPPORTED,
.get_flags = ip175d_get_flags,
.get_state = ip175d_get_state,
.update_state = ip175d_update_state,
.set_vlan_mode = ip175d_set_vlan_mode,
.reset = ip175d_reset,
};
struct ip175c_state {
struct switch_dev dev;
struct mii_bus *mii_bus;
@ -407,7 +457,7 @@ static int get_model(struct ip175c_state *state)
chip_no = ip_phy_read(state, 20, 0);
pr_debug("IP175C: Chip ID register reads %04x\n", chip_no);
if (chip_no == 0x175d) {
state->regs = &IP175C;
state->regs = &IP175D;
} else {
state->regs = &IP175C;
}
@ -419,6 +469,8 @@ static int get_model(struct ip175c_state *state)
return 0;
}
/*** Low-level functions for the older models ***/
/** Get only the vlan and router flags on the router **/
static int ip175c_get_flags(struct ip175c_state *state)
{
@ -727,6 +779,122 @@ static int ip175c_do_reset(struct ip175c_state *state)
return 0;
}
/*** Low-level functions for IP175D ***/
static int ip175d_get_flags(struct ip175c_state *state)
{
// We keep the configuration of the switch cached, so get doesn't do anything
return 0;
}
static int ip175d_get_state(struct ip175c_state *state)
{
// Again, the configuration is fully cached
return 0;
}
static int ip175d_update_state(struct ip175c_state *state)
{
unsigned int filter_mask = 0;
unsigned int ports[16], add[16], rem[16];
int i, j;
int err = 0;
for (i = 0; i < 16; i++) {
ports[i] = 0;
add[i] = 0;
rem[i] = 0;
if (!state->vlan_enabled) {
err |= ip_phy_write(state, 22, 14+i, i+1); // default tags
ports[i] = 0x3f;
continue;
}
if (!state->vlans[i].tag) {
// Reset the filter
err |= ip_phy_write(state, 22, 14+i, 0); // tag
continue;
}
filter_mask |= 1 << i;
err |= ip_phy_write(state, 22, 14+i, state->vlans[i].tag);
ports[i] = state->vlans[i].ports;
for (j = 0; j < 6; j++) {
if (ports[i] & (1 << j)) {
if (state->add_tag & (1 << j))
add[i] |= 1 << j;
if (state->remove_tag & (1 << j))
rem[i] |= 1 << j;
}
}
}
// Port masks, tag adds and removals
for (i = 0; i < 8; i++) {
err |= ip_phy_write(state, 23, i, ports[2*i] | (ports[2*i+1] << 8));
err |= ip_phy_write(state, 23, 8+i, add[2*i] | (add[2*i+1] << 8));
err |= ip_phy_write(state, 23, 16+i, rem[2*i] | (rem[2*i+1] << 8));
}
err |= ip_phy_write(state, 22, 10, filter_mask);
// Default VLAN tag for each port
for (i = 0; i < 6; i++)
err |= ip_phy_write(state, 22, 4+i, state->vlans[state->ports[i].pvid].tag);
return (err ? -EIO : 0);
}
static int ip175d_set_vlan_mode(struct ip175c_state *state)
{
int i;
int err = 0;
if (state->vlan_enabled) {
// VLAN classification rules: tag-based VLANs, use VID to classify,
// drop packets that cannot be classified.
err |= ip_phy_write_masked(state, 22, 0, 0x3fff, 0x003f);
// Ingress rules: CFI=1 dropped, null VID is untagged, VID=1 passed,
// VID=0xfff discarded, admin both tagged and untagged, ingress
// filters enabled.
err |= ip_phy_write_masked(state, 22, 1, 0x0fff, 0x0c3f);
// Egress rules: IGMP processing off, keep VLAN header off
err |= ip_phy_write_masked(state, 22, 2, 0x0fff, 0x0000);
} else {
// VLAN classification rules: everything off & clear table
err |= ip_phy_write_masked(state, 22, 0, 0xbfff, 0x8000);
// Ingress and egress rules: set to defaults
err |= ip_phy_write_masked(state, 22, 1, 0x0fff, 0x0c3f);
err |= ip_phy_write_masked(state, 22, 2, 0x0fff, 0x0000);
}
// Reset default VLAN for each port to 0
for (i = 0; i < 6; i++)
state->ports[i].pvid = 0;
err |= ip175d_update_state(state);
return (err ? -EIO : 0);
}
static int ip175d_reset(struct ip175c_state *state)
{
int err = 0;
// Disable the special tagging mode
err |= ip_phy_write_masked(state, 21, 22, 0x0003, 0x0000);
// Set 802.1q protocol type
err |= ip_phy_write(state, 22, 3, 0x8100);
state->vlan_enabled = 0;
err |= ip175d_set_vlan_mode(state);
return (err ? -EIO : 0);
}
/*** High-level functions ***/
static int ip175c_get_enable_vlan(struct switch_dev *dev, const struct switch_attr *attr, struct switch_val *val)
{
struct ip175c_state *state = dev->priv;