mirror of
https://github.com/Ysurac/openmptcprouter.git
synced 2025-03-09 15:40:20 +00:00
Update 6.12 kernel patches
This commit is contained in:
parent
bdb9b0046f
commit
9d83c70ced
247 changed files with 53301 additions and 589 deletions
1249
6.12/target/linux/generic/files/drivers/net/phy/adm6996.c
Normal file
1249
6.12/target/linux/generic/files/drivers/net/phy/adm6996.c
Normal file
File diff suppressed because it is too large
Load diff
186
6.12/target/linux/generic/files/drivers/net/phy/adm6996.h
Normal file
186
6.12/target/linux/generic/files/drivers/net/phy/adm6996.h
Normal file
|
@ -0,0 +1,186 @@
|
|||
/*
|
||||
* ADM6996 switch driver
|
||||
*
|
||||
* Copyright (c) 2008 Felix Fietkau <nbd@nbd.name>
|
||||
* Copyright (c) 2010,2011 Peter Lebbing <peter@digitalbrains.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License v2 as published by the
|
||||
* Free Software Foundation
|
||||
*/
|
||||
#ifndef __ADM6996_H
|
||||
#define __ADM6996_H
|
||||
|
||||
/*
|
||||
* ADM_PHY_PORTS: Number of ports with a PHY.
|
||||
* We only control ports 0 to 3, because if 4 is connected, it is most likely
|
||||
* not connected to the switch but to a separate MII and MAC for the WAN port.
|
||||
*/
|
||||
#define ADM_PHY_PORTS 4
|
||||
#define ADM_NUM_PORTS 6
|
||||
#define ADM_CPU_PORT 5
|
||||
|
||||
#define ADM_NUM_VLANS 16
|
||||
#define ADM_VLAN_MAX_ID 4094
|
||||
|
||||
enum admreg {
|
||||
ADM_EEPROM_BASE = 0x0,
|
||||
ADM_P0_CFG = ADM_EEPROM_BASE + 1,
|
||||
ADM_P1_CFG = ADM_EEPROM_BASE + 3,
|
||||
ADM_P2_CFG = ADM_EEPROM_BASE + 5,
|
||||
ADM_P3_CFG = ADM_EEPROM_BASE + 7,
|
||||
ADM_P4_CFG = ADM_EEPROM_BASE + 8,
|
||||
ADM_P5_CFG = ADM_EEPROM_BASE + 9,
|
||||
ADM_SYSC0 = ADM_EEPROM_BASE + 0xa,
|
||||
ADM_VLAN_PRIOMAP = ADM_EEPROM_BASE + 0xe,
|
||||
ADM_SYSC3 = ADM_EEPROM_BASE + 0x11,
|
||||
/* Input Force No Tag Enable */
|
||||
ADM_IFNTE = ADM_EEPROM_BASE + 0x20,
|
||||
ADM_VID_CHECK = ADM_EEPROM_BASE + 0x26,
|
||||
ADM_P0_PVID = ADM_EEPROM_BASE + 0x28,
|
||||
ADM_P1_PVID = ADM_EEPROM_BASE + 0x29,
|
||||
/* Output Tag Bypass Enable and P2 PVID */
|
||||
ADM_OTBE_P2_PVID = ADM_EEPROM_BASE + 0x2a,
|
||||
ADM_P3_P4_PVID = ADM_EEPROM_BASE + 0x2b,
|
||||
ADM_P5_PVID = ADM_EEPROM_BASE + 0x2c,
|
||||
ADM_EEPROM_EXT_BASE = 0x40,
|
||||
#define ADM_VLAN_FILT_L(n) (ADM_EEPROM_EXT_BASE + 2 * (n))
|
||||
#define ADM_VLAN_FILT_H(n) (ADM_EEPROM_EXT_BASE + 1 + 2 * (n))
|
||||
#define ADM_VLAN_MAP(n) (ADM_EEPROM_BASE + 0x13 + n)
|
||||
ADM_COUNTER_BASE = 0xa0,
|
||||
ADM_SIG0 = ADM_COUNTER_BASE + 0,
|
||||
ADM_SIG1 = ADM_COUNTER_BASE + 1,
|
||||
ADM_PS0 = ADM_COUNTER_BASE + 2,
|
||||
ADM_PS1 = ADM_COUNTER_BASE + 3,
|
||||
ADM_PS2 = ADM_COUNTER_BASE + 4,
|
||||
ADM_CL0 = ADM_COUNTER_BASE + 8, /* RxPacket */
|
||||
ADM_CL6 = ADM_COUNTER_BASE + 0x1a, /* RxByte */
|
||||
ADM_CL12 = ADM_COUNTER_BASE + 0x2c, /* TxPacket */
|
||||
ADM_CL18 = ADM_COUNTER_BASE + 0x3e, /* TxByte */
|
||||
ADM_CL24 = ADM_COUNTER_BASE + 0x50, /* Coll */
|
||||
ADM_CL30 = ADM_COUNTER_BASE + 0x62, /* Err */
|
||||
#define ADM_OFFSET_PORT(n) ((n * 4) - (n / 4) * 2 - (n / 5) * 2)
|
||||
ADM_PHY_BASE = 0x200,
|
||||
#define ADM_PHY_PORT(n) (ADM_PHY_BASE + (0x20 * n))
|
||||
};
|
||||
|
||||
/* Chip identification patterns */
|
||||
#define ADM_SIG0_MASK 0xffff
|
||||
#define ADM_SIG0_VAL 0x1023
|
||||
#define ADM_SIG1_MASK 0xffff
|
||||
#define ADM_SIG1_VAL 0x0007
|
||||
|
||||
enum {
|
||||
ADM_PHYCFG_COLTST = (1 << 7), /* Enable collision test */
|
||||
ADM_PHYCFG_DPLX = (1 << 8), /* Enable full duplex */
|
||||
ADM_PHYCFG_ANEN_RST = (1 << 9), /* Restart auto negotiation (self clear) */
|
||||
ADM_PHYCFG_ISO = (1 << 10), /* Isolate PHY */
|
||||
ADM_PHYCFG_PDN = (1 << 11), /* Power down PHY */
|
||||
ADM_PHYCFG_ANEN = (1 << 12), /* Enable auto negotiation */
|
||||
ADM_PHYCFG_SPEED_100 = (1 << 13), /* Enable 100 Mbit/s */
|
||||
ADM_PHYCFG_LPBK = (1 << 14), /* Enable loopback operation */
|
||||
ADM_PHYCFG_RST = (1 << 15), /* Reset the port (self clear) */
|
||||
ADM_PHYCFG_INIT = (
|
||||
ADM_PHYCFG_RST |
|
||||
ADM_PHYCFG_SPEED_100 |
|
||||
ADM_PHYCFG_ANEN |
|
||||
ADM_PHYCFG_ANEN_RST
|
||||
)
|
||||
};
|
||||
|
||||
enum {
|
||||
ADM_PORTCFG_FC = (1 << 0), /* Enable 802.x flow control */
|
||||
ADM_PORTCFG_AN = (1 << 1), /* Enable auto-negotiation */
|
||||
ADM_PORTCFG_SPEED_100 = (1 << 2), /* Enable 100 Mbit/s */
|
||||
ADM_PORTCFG_DPLX = (1 << 3), /* Enable full duplex */
|
||||
ADM_PORTCFG_OT = (1 << 4), /* Output tagged packets */
|
||||
ADM_PORTCFG_PD = (1 << 5), /* Port disable */
|
||||
ADM_PORTCFG_TV_PRIO = (1 << 6), /* 0 = VLAN based priority
|
||||
* 1 = TOS based priority */
|
||||
ADM_PORTCFG_PPE = (1 << 7), /* Port based priority enable */
|
||||
ADM_PORTCFG_PP_S = (1 << 8), /* Port based priority, 2 bits */
|
||||
ADM_PORTCFG_PVID_BASE = (1 << 10), /* Primary VLAN id, 4 bits */
|
||||
ADM_PORTCFG_FSE = (1 << 14), /* Fx select enable */
|
||||
ADM_PORTCFG_CAM = (1 << 15), /* Crossover Auto MDIX */
|
||||
|
||||
ADM_PORTCFG_INIT = (
|
||||
ADM_PORTCFG_FC |
|
||||
ADM_PORTCFG_AN |
|
||||
ADM_PORTCFG_SPEED_100 |
|
||||
ADM_PORTCFG_DPLX |
|
||||
ADM_PORTCFG_CAM
|
||||
),
|
||||
ADM_PORTCFG_CPU = (
|
||||
ADM_PORTCFG_FC |
|
||||
ADM_PORTCFG_SPEED_100 |
|
||||
ADM_PORTCFG_OT |
|
||||
ADM_PORTCFG_DPLX
|
||||
),
|
||||
};
|
||||
|
||||
#define ADM_PORTCFG_PPID(n) ((n & 0x3) << 8)
|
||||
#define ADM_PORTCFG_PVID(n) ((n & 0xf) << 10)
|
||||
#define ADM_PORTCFG_PVID_MASK (0xf << 10)
|
||||
|
||||
#define ADM_IFNTE_MASK (0x3f << 9)
|
||||
#define ADM_VID_CHECK_MASK (0x3f << 6)
|
||||
|
||||
#define ADM_P0_PVID_VAL(n) ((((n) & 0xff0) >> 4) << 0)
|
||||
#define ADM_P1_PVID_VAL(n) ((((n) & 0xff0) >> 4) << 0)
|
||||
#define ADM_P2_PVID_VAL(n) ((((n) & 0xff0) >> 4) << 0)
|
||||
#define ADM_P3_PVID_VAL(n) ((((n) & 0xff0) >> 4) << 0)
|
||||
#define ADM_P4_PVID_VAL(n) ((((n) & 0xff0) >> 4) << 8)
|
||||
#define ADM_P5_PVID_VAL(n) ((((n) & 0xff0) >> 4) << 0)
|
||||
#define ADM_P2_PVID_MASK 0xff
|
||||
|
||||
#define ADM_OTBE(n) (((n) & 0x3f) << 8)
|
||||
#define ADM_OTBE_MASK (0x3f << 8)
|
||||
|
||||
/* ADM_SYSC0 */
|
||||
enum {
|
||||
ADM_NTTE = (1 << 2), /* New Tag Transmit Enable */
|
||||
ADM_RVID1 = (1 << 8) /* Replace VLAN ID 1 */
|
||||
};
|
||||
|
||||
/* Tag Based VLAN in ADM_SYSC3 */
|
||||
#define ADM_MAC_CLONE BIT(4)
|
||||
#define ADM_TBV BIT(5)
|
||||
|
||||
static const u8 adm_portcfg[] = {
|
||||
[0] = ADM_P0_CFG,
|
||||
[1] = ADM_P1_CFG,
|
||||
[2] = ADM_P2_CFG,
|
||||
[3] = ADM_P3_CFG,
|
||||
[4] = ADM_P4_CFG,
|
||||
[5] = ADM_P5_CFG,
|
||||
};
|
||||
|
||||
/* Fields in ADM_VLAN_FILT_L(x) */
|
||||
#define ADM_VLAN_FILT_FID(n) (((n) & 0xf) << 12)
|
||||
#define ADM_VLAN_FILT_TAGGED(n) (((n) & 0x3f) << 6)
|
||||
#define ADM_VLAN_FILT_MEMBER(n) (((n) & 0x3f) << 0)
|
||||
#define ADM_VLAN_FILT_MEMBER_MASK 0x3f
|
||||
/* Fields in ADM_VLAN_FILT_H(x) */
|
||||
#define ADM_VLAN_FILT_VALID (1 << 15)
|
||||
#define ADM_VLAN_FILT_VID(n) (((n) & 0xfff) << 0)
|
||||
|
||||
/* Convert ports to a form for ADM6996L VLAN map */
|
||||
#define ADM_VLAN_FILT(ports) ((ports & 0x01) | ((ports & 0x02) << 1) | \
|
||||
((ports & 0x04) << 2) | ((ports & 0x08) << 3) | \
|
||||
((ports & 0x10) << 3) | ((ports & 0x20) << 3))
|
||||
|
||||
/* Port status register */
|
||||
enum {
|
||||
ADM_PS_LS = (1 << 0), /* Link status */
|
||||
ADM_PS_SS = (1 << 1), /* Speed status */
|
||||
ADM_PS_DS = (1 << 2), /* Duplex status */
|
||||
ADM_PS_FCS = (1 << 3) /* Flow control status */
|
||||
};
|
||||
|
||||
/*
|
||||
* Split the register address in phy id and register
|
||||
* it will get combined again by the mdio bus op
|
||||
*/
|
||||
#define PHYADDR(_reg) ((_reg >> 5) & 0xff), (_reg & 0x1f)
|
||||
|
||||
#endif
|
2909
6.12/target/linux/generic/files/drivers/net/phy/ar8216.c
Normal file
2909
6.12/target/linux/generic/files/drivers/net/phy/ar8216.c
Normal file
File diff suppressed because it is too large
Load diff
725
6.12/target/linux/generic/files/drivers/net/phy/ar8216.h
Normal file
725
6.12/target/linux/generic/files/drivers/net/phy/ar8216.h
Normal file
|
@ -0,0 +1,725 @@
|
|||
/*
|
||||
* ar8216.h: AR8216 switch driver
|
||||
*
|
||||
* Copyright (C) 2009 Felix Fietkau <nbd@nbd.name>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#ifndef __AR8216_H
|
||||
#define __AR8216_H
|
||||
|
||||
#define BITS(_s, _n) (((1UL << (_n)) - 1) << _s)
|
||||
|
||||
#define AR8XXX_CAP_GIGE BIT(0)
|
||||
#define AR8XXX_CAP_MIB_COUNTERS BIT(1)
|
||||
|
||||
#define AR8XXX_NUM_PHYS 5
|
||||
#define AR8216_PORT_CPU 0
|
||||
#define AR8216_NUM_PORTS 6
|
||||
#define AR8216_NUM_VLANS 16
|
||||
#define AR7240SW_NUM_PORTS 5
|
||||
#define AR8316_NUM_VLANS 4096
|
||||
|
||||
/* size of the vlan table */
|
||||
#define AR8X16_MAX_VLANS 128
|
||||
#define AR83X7_MAX_VLANS 4096
|
||||
#define AR8XXX_MAX_VLANS AR83X7_MAX_VLANS
|
||||
|
||||
#define AR8X16_PROBE_RETRIES 10
|
||||
#define AR8X16_MAX_PORTS 8
|
||||
|
||||
#define AR8XXX_REG_ARL_CTRL_AGE_TIME_SECS 7
|
||||
#define AR8XXX_DEFAULT_ARL_AGE_TIME 300
|
||||
|
||||
/* Atheros specific MII registers */
|
||||
#define MII_ATH_MMD_ADDR 0x0d
|
||||
#define MII_ATH_MMD_DATA 0x0e
|
||||
#define MII_ATH_DBG_ADDR 0x1d
|
||||
#define MII_ATH_DBG_DATA 0x1e
|
||||
|
||||
#define AR8216_REG_CTRL 0x0000
|
||||
#define AR8216_CTRL_REVISION BITS(0, 8)
|
||||
#define AR8216_CTRL_REVISION_S 0
|
||||
#define AR8216_CTRL_VERSION BITS(8, 8)
|
||||
#define AR8216_CTRL_VERSION_S 8
|
||||
#define AR8216_CTRL_RESET BIT(31)
|
||||
|
||||
#define AR8216_REG_FLOOD_MASK 0x002C
|
||||
#define AR8216_FM_UNI_DEST_PORTS BITS(0, 6)
|
||||
#define AR8216_FM_MULTI_DEST_PORTS BITS(16, 6)
|
||||
#define AR8216_FM_CPU_BROADCAST_EN BIT(26)
|
||||
#define AR8229_FLOOD_MASK_UC_DP(_p) BIT(_p)
|
||||
#define AR8229_FLOOD_MASK_MC_DP(_p) BIT(16 + (_p))
|
||||
#define AR8229_FLOOD_MASK_BC_DP(_p) BIT(25 + (_p))
|
||||
|
||||
#define AR8216_REG_GLOBAL_CTRL 0x0030
|
||||
#define AR8216_GCTRL_MTU BITS(0, 11)
|
||||
#define AR8236_GCTRL_MTU BITS(0, 14)
|
||||
#define AR8316_GCTRL_MTU BITS(0, 14)
|
||||
|
||||
#define AR8216_REG_VTU 0x0040
|
||||
#define AR8216_VTU_OP BITS(0, 3)
|
||||
#define AR8216_VTU_OP_NOOP 0x0
|
||||
#define AR8216_VTU_OP_FLUSH 0x1
|
||||
#define AR8216_VTU_OP_LOAD 0x2
|
||||
#define AR8216_VTU_OP_PURGE 0x3
|
||||
#define AR8216_VTU_OP_REMOVE_PORT 0x4
|
||||
#define AR8216_VTU_ACTIVE BIT(3)
|
||||
#define AR8216_VTU_FULL BIT(4)
|
||||
#define AR8216_VTU_PORT BITS(8, 4)
|
||||
#define AR8216_VTU_PORT_S 8
|
||||
#define AR8216_VTU_VID BITS(16, 12)
|
||||
#define AR8216_VTU_VID_S 16
|
||||
#define AR8216_VTU_PRIO BITS(28, 3)
|
||||
#define AR8216_VTU_PRIO_S 28
|
||||
#define AR8216_VTU_PRIO_EN BIT(31)
|
||||
|
||||
#define AR8216_REG_VTU_DATA 0x0044
|
||||
#define AR8216_VTUDATA_MEMBER BITS(0, 10)
|
||||
#define AR8236_VTUDATA_MEMBER BITS(0, 7)
|
||||
#define AR8216_VTUDATA_VALID BIT(11)
|
||||
|
||||
#define AR8216_REG_ATU_FUNC0 0x0050
|
||||
#define AR8216_ATU_OP BITS(0, 3)
|
||||
#define AR8216_ATU_OP_NOOP 0x0
|
||||
#define AR8216_ATU_OP_FLUSH 0x1
|
||||
#define AR8216_ATU_OP_LOAD 0x2
|
||||
#define AR8216_ATU_OP_PURGE 0x3
|
||||
#define AR8216_ATU_OP_FLUSH_UNLOCKED 0x4
|
||||
#define AR8216_ATU_OP_FLUSH_PORT 0x5
|
||||
#define AR8216_ATU_OP_GET_NEXT 0x6
|
||||
#define AR8216_ATU_ACTIVE BIT(3)
|
||||
#define AR8216_ATU_PORT_NUM BITS(8, 4)
|
||||
#define AR8216_ATU_PORT_NUM_S 8
|
||||
#define AR8216_ATU_FULL_VIO BIT(12)
|
||||
#define AR8216_ATU_ADDR5 BITS(16, 8)
|
||||
#define AR8216_ATU_ADDR5_S 16
|
||||
#define AR8216_ATU_ADDR4 BITS(24, 8)
|
||||
#define AR8216_ATU_ADDR4_S 24
|
||||
|
||||
#define AR8216_REG_ATU_FUNC1 0x0054
|
||||
#define AR8216_ATU_ADDR3 BITS(0, 8)
|
||||
#define AR8216_ATU_ADDR3_S 0
|
||||
#define AR8216_ATU_ADDR2 BITS(8, 8)
|
||||
#define AR8216_ATU_ADDR2_S 8
|
||||
#define AR8216_ATU_ADDR1 BITS(16, 8)
|
||||
#define AR8216_ATU_ADDR1_S 16
|
||||
#define AR8216_ATU_ADDR0 BITS(24, 8)
|
||||
#define AR8216_ATU_ADDR0_S 24
|
||||
|
||||
#define AR8216_REG_ATU_FUNC2 0x0058
|
||||
#define AR8216_ATU_PORTS BITS(0, 6)
|
||||
#define AR8216_ATU_PORTS_S 0
|
||||
#define AR8216_ATU_PORT0 BIT(0)
|
||||
#define AR8216_ATU_PORT1 BIT(1)
|
||||
#define AR8216_ATU_PORT2 BIT(2)
|
||||
#define AR8216_ATU_PORT3 BIT(3)
|
||||
#define AR8216_ATU_PORT4 BIT(4)
|
||||
#define AR8216_ATU_PORT5 BIT(5)
|
||||
#define AR8216_ATU_STATUS BITS(16, 4)
|
||||
#define AR8216_ATU_STATUS_S 16
|
||||
|
||||
#define AR8216_REG_ATU_CTRL 0x005C
|
||||
#define AR8216_ATU_CTRL_AGE_EN BIT(17)
|
||||
#define AR8216_ATU_CTRL_AGE_TIME BITS(0, 16)
|
||||
#define AR8216_ATU_CTRL_AGE_TIME_S 0
|
||||
#define AR8236_ATU_CTRL_RES BIT(20)
|
||||
#define AR8216_ATU_CTRL_LEARN_CHANGE BIT(18)
|
||||
#define AR8216_ATU_CTRL_RESERVED BIT(19)
|
||||
#define AR8216_ATU_CTRL_ARP_EN BIT(20)
|
||||
|
||||
#define AR8216_REG_TAG_PRIORITY 0x0070
|
||||
|
||||
#define AR8216_REG_SERVICE_TAG 0x0074
|
||||
#define AR8216_SERVICE_TAG_M BITS(0, 16)
|
||||
|
||||
#define AR8216_REG_MIB_FUNC 0x0080
|
||||
#define AR8216_MIB_TIMER BITS(0, 16)
|
||||
#define AR8216_MIB_AT_HALF_EN BIT(16)
|
||||
#define AR8216_MIB_BUSY BIT(17)
|
||||
#define AR8216_MIB_FUNC BITS(24, 3)
|
||||
#define AR8216_MIB_FUNC_S 24
|
||||
#define AR8216_MIB_FUNC_NO_OP 0x0
|
||||
#define AR8216_MIB_FUNC_FLUSH 0x1
|
||||
#define AR8216_MIB_FUNC_CAPTURE 0x3
|
||||
#define AR8236_MIB_EN BIT(30)
|
||||
|
||||
#define AR8216_REG_GLOBAL_CPUPORT 0x0078
|
||||
#define AR8216_GLOBAL_CPUPORT_MIRROR_PORT BITS(4, 4)
|
||||
#define AR8216_GLOBAL_CPUPORT_MIRROR_PORT_S 4
|
||||
#define AR8216_GLOBAL_CPUPORT_EN BIT(8)
|
||||
|
||||
#define AR8216_REG_MDIO_CTRL 0x98
|
||||
#define AR8216_MDIO_CTRL_DATA_M BITS(0, 16)
|
||||
#define AR8216_MDIO_CTRL_REG_ADDR_S 16
|
||||
#define AR8216_MDIO_CTRL_PHY_ADDR_S 21
|
||||
#define AR8216_MDIO_CTRL_CMD_WRITE 0
|
||||
#define AR8216_MDIO_CTRL_CMD_READ BIT(27)
|
||||
#define AR8216_MDIO_CTRL_MASTER_EN BIT(30)
|
||||
#define AR8216_MDIO_CTRL_BUSY BIT(31)
|
||||
|
||||
#define AR8216_PORT_OFFSET(_i) (0x0100 * (_i + 1))
|
||||
#define AR8216_REG_PORT_STATUS(_i) (AR8216_PORT_OFFSET(_i) + 0x0000)
|
||||
#define AR8216_PORT_STATUS_SPEED BITS(0,2)
|
||||
#define AR8216_PORT_STATUS_SPEED_S 0
|
||||
#define AR8216_PORT_STATUS_TXMAC BIT(2)
|
||||
#define AR8216_PORT_STATUS_RXMAC BIT(3)
|
||||
#define AR8216_PORT_STATUS_TXFLOW BIT(4)
|
||||
#define AR8216_PORT_STATUS_RXFLOW BIT(5)
|
||||
#define AR8216_PORT_STATUS_DUPLEX BIT(6)
|
||||
#define AR8216_PORT_STATUS_LINK_UP BIT(8)
|
||||
#define AR8216_PORT_STATUS_LINK_AUTO BIT(9)
|
||||
#define AR8216_PORT_STATUS_LINK_PAUSE BIT(10)
|
||||
#define AR8216_PORT_STATUS_FLOW_CONTROL BIT(12)
|
||||
|
||||
#define AR8216_REG_PORT_CTRL(_i) (AR8216_PORT_OFFSET(_i) + 0x0004)
|
||||
|
||||
/* port forwarding state */
|
||||
#define AR8216_PORT_CTRL_STATE BITS(0, 3)
|
||||
#define AR8216_PORT_CTRL_STATE_S 0
|
||||
|
||||
#define AR8216_PORT_CTRL_LEARN_LOCK BIT(7)
|
||||
|
||||
/* egress 802.1q mode */
|
||||
#define AR8216_PORT_CTRL_VLAN_MODE BITS(8, 2)
|
||||
#define AR8216_PORT_CTRL_VLAN_MODE_S 8
|
||||
|
||||
#define AR8216_PORT_CTRL_IGMP_SNOOP BIT(10)
|
||||
#define AR8216_PORT_CTRL_HEADER BIT(11)
|
||||
#define AR8216_PORT_CTRL_MAC_LOOP BIT(12)
|
||||
#define AR8216_PORT_CTRL_SINGLE_VLAN BIT(13)
|
||||
#define AR8216_PORT_CTRL_LEARN BIT(14)
|
||||
#define AR8216_PORT_CTRL_MIRROR_TX BIT(16)
|
||||
#define AR8216_PORT_CTRL_MIRROR_RX BIT(17)
|
||||
|
||||
#define AR8216_REG_PORT_VLAN(_i) (AR8216_PORT_OFFSET(_i) + 0x0008)
|
||||
|
||||
#define AR8216_PORT_VLAN_DEFAULT_ID BITS(0, 12)
|
||||
#define AR8216_PORT_VLAN_DEFAULT_ID_S 0
|
||||
|
||||
#define AR8216_PORT_VLAN_DEST_PORTS BITS(16, 9)
|
||||
#define AR8216_PORT_VLAN_DEST_PORTS_S 16
|
||||
|
||||
/* bit0 added to the priority field of egress frames */
|
||||
#define AR8216_PORT_VLAN_TX_PRIO BIT(27)
|
||||
|
||||
/* port default priority */
|
||||
#define AR8216_PORT_VLAN_PRIORITY BITS(28, 2)
|
||||
#define AR8216_PORT_VLAN_PRIORITY_S 28
|
||||
|
||||
/* ingress 802.1q mode */
|
||||
#define AR8216_PORT_VLAN_MODE BITS(30, 2)
|
||||
#define AR8216_PORT_VLAN_MODE_S 30
|
||||
|
||||
#define AR8216_REG_PORT_RATE(_i) (AR8216_PORT_OFFSET(_i) + 0x000c)
|
||||
#define AR8216_REG_PORT_PRIO(_i) (AR8216_PORT_OFFSET(_i) + 0x0010)
|
||||
|
||||
#define AR8216_STATS_RXBROAD 0x00
|
||||
#define AR8216_STATS_RXPAUSE 0x04
|
||||
#define AR8216_STATS_RXMULTI 0x08
|
||||
#define AR8216_STATS_RXFCSERR 0x0c
|
||||
#define AR8216_STATS_RXALIGNERR 0x10
|
||||
#define AR8216_STATS_RXRUNT 0x14
|
||||
#define AR8216_STATS_RXFRAGMENT 0x18
|
||||
#define AR8216_STATS_RX64BYTE 0x1c
|
||||
#define AR8216_STATS_RX128BYTE 0x20
|
||||
#define AR8216_STATS_RX256BYTE 0x24
|
||||
#define AR8216_STATS_RX512BYTE 0x28
|
||||
#define AR8216_STATS_RX1024BYTE 0x2c
|
||||
#define AR8216_STATS_RXMAXBYTE 0x30
|
||||
#define AR8216_STATS_RXTOOLONG 0x34
|
||||
#define AR8216_STATS_RXGOODBYTE 0x38
|
||||
#define AR8216_STATS_RXBADBYTE 0x40
|
||||
#define AR8216_STATS_RXOVERFLOW 0x48
|
||||
#define AR8216_STATS_FILTERED 0x4c
|
||||
#define AR8216_STATS_TXBROAD 0x50
|
||||
#define AR8216_STATS_TXPAUSE 0x54
|
||||
#define AR8216_STATS_TXMULTI 0x58
|
||||
#define AR8216_STATS_TXUNDERRUN 0x5c
|
||||
#define AR8216_STATS_TX64BYTE 0x60
|
||||
#define AR8216_STATS_TX128BYTE 0x64
|
||||
#define AR8216_STATS_TX256BYTE 0x68
|
||||
#define AR8216_STATS_TX512BYTE 0x6c
|
||||
#define AR8216_STATS_TX1024BYTE 0x70
|
||||
#define AR8216_STATS_TXMAXBYTE 0x74
|
||||
#define AR8216_STATS_TXOVERSIZE 0x78
|
||||
#define AR8216_STATS_TXBYTE 0x7c
|
||||
#define AR8216_STATS_TXCOLLISION 0x84
|
||||
#define AR8216_STATS_TXABORTCOL 0x88
|
||||
#define AR8216_STATS_TXMULTICOL 0x8c
|
||||
#define AR8216_STATS_TXSINGLECOL 0x90
|
||||
#define AR8216_STATS_TXEXCDEFER 0x94
|
||||
#define AR8216_STATS_TXDEFER 0x98
|
||||
#define AR8216_STATS_TXLATECOL 0x9c
|
||||
|
||||
#define AR8216_MIB_RXB_ID 14 /* RxGoodByte */
|
||||
#define AR8216_MIB_TXB_ID 29 /* TxByte */
|
||||
|
||||
#define AR8229_REG_OPER_MODE0 0x04
|
||||
#define AR8229_OPER_MODE0_MAC_GMII_EN BIT(6)
|
||||
#define AR8229_OPER_MODE0_PHY_MII_EN BIT(10)
|
||||
|
||||
#define AR8229_REG_OPER_MODE1 0x08
|
||||
#define AR8229_REG_OPER_MODE1_PHY4_MII_EN BIT(28)
|
||||
|
||||
#define AR8229_REG_QM_CTRL 0x3c
|
||||
#define AR8229_QM_CTRL_ARP_EN BIT(15)
|
||||
|
||||
#define AR8236_REG_PORT_VLAN(_i) (AR8216_PORT_OFFSET((_i)) + 0x0008)
|
||||
#define AR8236_PORT_VLAN_DEFAULT_ID BITS(16, 12)
|
||||
#define AR8236_PORT_VLAN_DEFAULT_ID_S 16
|
||||
#define AR8236_PORT_VLAN_PRIORITY BITS(29, 3)
|
||||
#define AR8236_PORT_VLAN_PRIORITY_S 28
|
||||
|
||||
#define AR8236_REG_PORT_VLAN2(_i) (AR8216_PORT_OFFSET((_i)) + 0x000c)
|
||||
#define AR8236_PORT_VLAN2_MEMBER BITS(16, 7)
|
||||
#define AR8236_PORT_VLAN2_MEMBER_S 16
|
||||
#define AR8236_PORT_VLAN2_TX_PRIO BIT(23)
|
||||
#define AR8236_PORT_VLAN2_VLAN_MODE BITS(30, 2)
|
||||
#define AR8236_PORT_VLAN2_VLAN_MODE_S 30
|
||||
|
||||
#define AR8236_STATS_RXBROAD 0x00
|
||||
#define AR8236_STATS_RXPAUSE 0x04
|
||||
#define AR8236_STATS_RXMULTI 0x08
|
||||
#define AR8236_STATS_RXFCSERR 0x0c
|
||||
#define AR8236_STATS_RXALIGNERR 0x10
|
||||
#define AR8236_STATS_RXRUNT 0x14
|
||||
#define AR8236_STATS_RXFRAGMENT 0x18
|
||||
#define AR8236_STATS_RX64BYTE 0x1c
|
||||
#define AR8236_STATS_RX128BYTE 0x20
|
||||
#define AR8236_STATS_RX256BYTE 0x24
|
||||
#define AR8236_STATS_RX512BYTE 0x28
|
||||
#define AR8236_STATS_RX1024BYTE 0x2c
|
||||
#define AR8236_STATS_RX1518BYTE 0x30
|
||||
#define AR8236_STATS_RXMAXBYTE 0x34
|
||||
#define AR8236_STATS_RXTOOLONG 0x38
|
||||
#define AR8236_STATS_RXGOODBYTE 0x3c
|
||||
#define AR8236_STATS_RXBADBYTE 0x44
|
||||
#define AR8236_STATS_RXOVERFLOW 0x4c
|
||||
#define AR8236_STATS_FILTERED 0x50
|
||||
#define AR8236_STATS_TXBROAD 0x54
|
||||
#define AR8236_STATS_TXPAUSE 0x58
|
||||
#define AR8236_STATS_TXMULTI 0x5c
|
||||
#define AR8236_STATS_TXUNDERRUN 0x60
|
||||
#define AR8236_STATS_TX64BYTE 0x64
|
||||
#define AR8236_STATS_TX128BYTE 0x68
|
||||
#define AR8236_STATS_TX256BYTE 0x6c
|
||||
#define AR8236_STATS_TX512BYTE 0x70
|
||||
#define AR8236_STATS_TX1024BYTE 0x74
|
||||
#define AR8236_STATS_TX1518BYTE 0x78
|
||||
#define AR8236_STATS_TXMAXBYTE 0x7c
|
||||
#define AR8236_STATS_TXOVERSIZE 0x80
|
||||
#define AR8236_STATS_TXBYTE 0x84
|
||||
#define AR8236_STATS_TXCOLLISION 0x8c
|
||||
#define AR8236_STATS_TXABORTCOL 0x90
|
||||
#define AR8236_STATS_TXMULTICOL 0x94
|
||||
#define AR8236_STATS_TXSINGLECOL 0x98
|
||||
#define AR8236_STATS_TXEXCDEFER 0x9c
|
||||
#define AR8236_STATS_TXDEFER 0xa0
|
||||
#define AR8236_STATS_TXLATECOL 0xa4
|
||||
|
||||
#define AR8236_MIB_RXB_ID 15 /* RxGoodByte */
|
||||
#define AR8236_MIB_TXB_ID 31 /* TxByte */
|
||||
|
||||
#define AR8316_REG_POSTRIP 0x0008
|
||||
#define AR8316_POSTRIP_MAC0_GMII_EN BIT(0)
|
||||
#define AR8316_POSTRIP_MAC0_RGMII_EN BIT(1)
|
||||
#define AR8316_POSTRIP_PHY4_GMII_EN BIT(2)
|
||||
#define AR8316_POSTRIP_PHY4_RGMII_EN BIT(3)
|
||||
#define AR8316_POSTRIP_MAC0_MAC_MODE BIT(4)
|
||||
#define AR8316_POSTRIP_RTL_MODE BIT(5)
|
||||
#define AR8316_POSTRIP_RGMII_RXCLK_DELAY_EN BIT(6)
|
||||
#define AR8316_POSTRIP_RGMII_TXCLK_DELAY_EN BIT(7)
|
||||
#define AR8316_POSTRIP_SERDES_EN BIT(8)
|
||||
#define AR8316_POSTRIP_SEL_ANA_RST BIT(9)
|
||||
#define AR8316_POSTRIP_GATE_25M_EN BIT(10)
|
||||
#define AR8316_POSTRIP_SEL_CLK25M BIT(11)
|
||||
#define AR8316_POSTRIP_HIB_PULSE_HW BIT(12)
|
||||
#define AR8316_POSTRIP_DBG_MODE_I BIT(13)
|
||||
#define AR8316_POSTRIP_MAC5_MAC_MODE BIT(14)
|
||||
#define AR8316_POSTRIP_MAC5_PHY_MODE BIT(15)
|
||||
#define AR8316_POSTRIP_POWER_DOWN_HW BIT(16)
|
||||
#define AR8316_POSTRIP_LPW_STATE_EN BIT(17)
|
||||
#define AR8316_POSTRIP_MAN_EN BIT(18)
|
||||
#define AR8316_POSTRIP_PHY_PLL_ON BIT(19)
|
||||
#define AR8316_POSTRIP_LPW_EXIT BIT(20)
|
||||
#define AR8316_POSTRIP_TXDELAY_S0 BIT(21)
|
||||
#define AR8316_POSTRIP_TXDELAY_S1 BIT(22)
|
||||
#define AR8316_POSTRIP_RXDELAY_S0 BIT(23)
|
||||
#define AR8316_POSTRIP_LED_OPEN_EN BIT(24)
|
||||
#define AR8316_POSTRIP_SPI_EN BIT(25)
|
||||
#define AR8316_POSTRIP_RXDELAY_S1 BIT(26)
|
||||
#define AR8316_POSTRIP_POWER_ON_SEL BIT(31)
|
||||
|
||||
/* port speed */
|
||||
enum {
|
||||
AR8216_PORT_SPEED_10M = 0,
|
||||
AR8216_PORT_SPEED_100M = 1,
|
||||
AR8216_PORT_SPEED_1000M = 2,
|
||||
AR8216_PORT_SPEED_ERR = 3,
|
||||
};
|
||||
|
||||
/* ingress 802.1q mode */
|
||||
enum {
|
||||
AR8216_IN_PORT_ONLY = 0,
|
||||
AR8216_IN_PORT_FALLBACK = 1,
|
||||
AR8216_IN_VLAN_ONLY = 2,
|
||||
AR8216_IN_SECURE = 3
|
||||
};
|
||||
|
||||
/* egress 802.1q mode */
|
||||
enum {
|
||||
AR8216_OUT_KEEP = 0,
|
||||
AR8216_OUT_STRIP_VLAN = 1,
|
||||
AR8216_OUT_ADD_VLAN = 2
|
||||
};
|
||||
|
||||
/* port forwarding state */
|
||||
enum {
|
||||
AR8216_PORT_STATE_DISABLED = 0,
|
||||
AR8216_PORT_STATE_BLOCK = 1,
|
||||
AR8216_PORT_STATE_LISTEN = 2,
|
||||
AR8216_PORT_STATE_LEARN = 3,
|
||||
AR8216_PORT_STATE_FORWARD = 4
|
||||
};
|
||||
|
||||
/* mib counter type */
|
||||
enum {
|
||||
AR8XXX_MIB_BASIC = 0,
|
||||
AR8XXX_MIB_EXTENDED = 1
|
||||
};
|
||||
|
||||
enum {
|
||||
AR8XXX_VER_AR8216 = 0x01,
|
||||
AR8XXX_VER_AR8236 = 0x03,
|
||||
AR8XXX_VER_AR8316 = 0x10,
|
||||
AR8XXX_VER_AR8327 = 0x12,
|
||||
AR8XXX_VER_AR8337 = 0x13,
|
||||
};
|
||||
|
||||
#define AR8XXX_NUM_ARL_RECORDS 100
|
||||
|
||||
enum arl_op {
|
||||
AR8XXX_ARL_INITIALIZE,
|
||||
AR8XXX_ARL_GET_NEXT
|
||||
};
|
||||
|
||||
struct arl_entry {
|
||||
u16 portmap;
|
||||
u8 mac[6];
|
||||
};
|
||||
|
||||
struct ar8xxx_priv;
|
||||
|
||||
struct ar8xxx_mib_desc {
|
||||
unsigned int size;
|
||||
unsigned int offset;
|
||||
const char *name;
|
||||
u8 type;
|
||||
};
|
||||
|
||||
struct ar8xxx_chip {
|
||||
unsigned long caps;
|
||||
bool config_at_probe;
|
||||
bool mii_lo_first;
|
||||
|
||||
/* parameters to calculate REG_PORT_STATS_BASE */
|
||||
unsigned reg_port_stats_start;
|
||||
unsigned reg_port_stats_length;
|
||||
|
||||
unsigned reg_arl_ctrl;
|
||||
|
||||
int (*hw_init)(struct ar8xxx_priv *priv);
|
||||
void (*cleanup)(struct ar8xxx_priv *priv);
|
||||
|
||||
const char *name;
|
||||
int vlans;
|
||||
int ports;
|
||||
const struct switch_dev_ops *swops;
|
||||
|
||||
void (*init_globals)(struct ar8xxx_priv *priv);
|
||||
void (*init_port)(struct ar8xxx_priv *priv, int port);
|
||||
void (*setup_port)(struct ar8xxx_priv *priv, int port, u32 members);
|
||||
u32 (*read_port_status)(struct ar8xxx_priv *priv, int port);
|
||||
u32 (*read_port_eee_status)(struct ar8xxx_priv *priv, int port);
|
||||
int (*atu_flush)(struct ar8xxx_priv *priv);
|
||||
int (*atu_flush_port)(struct ar8xxx_priv *priv, int port);
|
||||
void (*vtu_flush)(struct ar8xxx_priv *priv);
|
||||
void (*vtu_load_vlan)(struct ar8xxx_priv *priv, u32 vid, u32 port_mask);
|
||||
void (*phy_fixup)(struct ar8xxx_priv *priv, int phy);
|
||||
void (*set_mirror_regs)(struct ar8xxx_priv *priv);
|
||||
void (*get_arl_entry)(struct ar8xxx_priv *priv, struct arl_entry *a,
|
||||
u32 *status, enum arl_op op);
|
||||
int (*sw_hw_apply)(struct switch_dev *dev);
|
||||
void (*phy_rgmii_set)(struct ar8xxx_priv *priv, struct phy_device *phydev);
|
||||
int (*phy_read)(struct ar8xxx_priv *priv, int addr, int regnum);
|
||||
int (*phy_write)(struct ar8xxx_priv *priv, int addr, int regnum, u16 val);
|
||||
|
||||
const struct ar8xxx_mib_desc *mib_decs;
|
||||
unsigned num_mibs;
|
||||
unsigned mib_func;
|
||||
int mib_rxb_id;
|
||||
int mib_txb_id;
|
||||
};
|
||||
|
||||
struct ar8xxx_priv {
|
||||
struct switch_dev dev;
|
||||
struct mii_bus *mii_bus;
|
||||
struct mii_bus *sw_mii_bus;
|
||||
struct phy_device *phy;
|
||||
struct device *pdev;
|
||||
|
||||
int (*get_port_link)(unsigned port);
|
||||
|
||||
const struct net_device_ops *ndo_old;
|
||||
struct net_device_ops ndo;
|
||||
struct mutex reg_mutex;
|
||||
u8 chip_ver;
|
||||
u8 chip_rev;
|
||||
const struct ar8xxx_chip *chip;
|
||||
void *chip_data;
|
||||
bool initialized;
|
||||
bool port4_phy;
|
||||
char buf[2048];
|
||||
struct arl_entry arl_table[AR8XXX_NUM_ARL_RECORDS];
|
||||
char arl_buf[AR8XXX_NUM_ARL_RECORDS * 32 + 256];
|
||||
bool link_up[AR8X16_MAX_PORTS];
|
||||
|
||||
bool init;
|
||||
|
||||
struct mutex mib_lock;
|
||||
struct delayed_work mib_work;
|
||||
u64 *mib_stats;
|
||||
u32 mib_poll_interval;
|
||||
u8 mib_type;
|
||||
|
||||
struct list_head list;
|
||||
unsigned int use_count;
|
||||
|
||||
/* all fields below are cleared on reset */
|
||||
struct_group(ar8xxx_priv_volatile,
|
||||
bool vlan;
|
||||
|
||||
u16 vlan_id[AR8XXX_MAX_VLANS];
|
||||
u8 vlan_table[AR8XXX_MAX_VLANS];
|
||||
u8 vlan_tagged;
|
||||
u16 pvid[AR8X16_MAX_PORTS];
|
||||
int arl_age_time;
|
||||
|
||||
/* mirroring */
|
||||
bool mirror_rx;
|
||||
bool mirror_tx;
|
||||
int source_port;
|
||||
int monitor_port;
|
||||
u8 port_vlan_prio[AR8X16_MAX_PORTS];
|
||||
);
|
||||
};
|
||||
|
||||
u32
|
||||
ar8xxx_mii_read32(struct ar8xxx_priv *priv, int phy_id, int regnum);
|
||||
void
|
||||
ar8xxx_mii_write32(struct ar8xxx_priv *priv, int phy_id, int regnum, u32 val);
|
||||
u32
|
||||
ar8xxx_read(struct ar8xxx_priv *priv, int reg);
|
||||
void
|
||||
ar8xxx_write(struct ar8xxx_priv *priv, int reg, u32 val);
|
||||
u32
|
||||
ar8xxx_rmw(struct ar8xxx_priv *priv, int reg, u32 mask, u32 val);
|
||||
|
||||
void
|
||||
ar8xxx_phy_dbg_read(struct ar8xxx_priv *priv, int phy_addr,
|
||||
u16 dbg_addr, u16 *dbg_data);
|
||||
void
|
||||
ar8xxx_phy_dbg_write(struct ar8xxx_priv *priv, int phy_addr,
|
||||
u16 dbg_addr, u16 dbg_data);
|
||||
void
|
||||
ar8xxx_phy_mmd_write(struct ar8xxx_priv *priv, int phy_addr, u16 addr, u16 reg, u16 data);
|
||||
u16
|
||||
ar8xxx_phy_mmd_read(struct ar8xxx_priv *priv, int phy_addr, u16 addr, u16 reg);
|
||||
void
|
||||
ar8xxx_phy_init(struct ar8xxx_priv *priv);
|
||||
int
|
||||
ar8xxx_sw_set_vlan(struct switch_dev *dev, const struct switch_attr *attr,
|
||||
struct switch_val *val);
|
||||
int
|
||||
ar8xxx_sw_get_vlan(struct switch_dev *dev, const struct switch_attr *attr,
|
||||
struct switch_val *val);
|
||||
int
|
||||
ar8xxx_sw_set_reset_mibs(struct switch_dev *dev,
|
||||
const struct switch_attr *attr,
|
||||
struct switch_val *val);
|
||||
int
|
||||
ar8xxx_sw_set_mib_poll_interval(struct switch_dev *dev,
|
||||
const struct switch_attr *attr,
|
||||
struct switch_val *val);
|
||||
int
|
||||
ar8xxx_sw_get_mib_poll_interval(struct switch_dev *dev,
|
||||
const struct switch_attr *attr,
|
||||
struct switch_val *val);
|
||||
int
|
||||
ar8xxx_sw_set_mib_type(struct switch_dev *dev,
|
||||
const struct switch_attr *attr,
|
||||
struct switch_val *val);
|
||||
int
|
||||
ar8xxx_sw_get_mib_type(struct switch_dev *dev,
|
||||
const struct switch_attr *attr,
|
||||
struct switch_val *val);
|
||||
int
|
||||
ar8xxx_sw_set_mirror_rx_enable(struct switch_dev *dev,
|
||||
const struct switch_attr *attr,
|
||||
struct switch_val *val);
|
||||
int
|
||||
ar8xxx_sw_get_mirror_rx_enable(struct switch_dev *dev,
|
||||
const struct switch_attr *attr,
|
||||
struct switch_val *val);
|
||||
int
|
||||
ar8xxx_sw_set_mirror_tx_enable(struct switch_dev *dev,
|
||||
const struct switch_attr *attr,
|
||||
struct switch_val *val);
|
||||
int
|
||||
ar8xxx_sw_get_mirror_tx_enable(struct switch_dev *dev,
|
||||
const struct switch_attr *attr,
|
||||
struct switch_val *val);
|
||||
int
|
||||
ar8xxx_sw_set_mirror_monitor_port(struct switch_dev *dev,
|
||||
const struct switch_attr *attr,
|
||||
struct switch_val *val);
|
||||
int
|
||||
ar8xxx_sw_get_mirror_monitor_port(struct switch_dev *dev,
|
||||
const struct switch_attr *attr,
|
||||
struct switch_val *val);
|
||||
int
|
||||
ar8xxx_sw_set_mirror_source_port(struct switch_dev *dev,
|
||||
const struct switch_attr *attr,
|
||||
struct switch_val *val);
|
||||
int
|
||||
ar8xxx_sw_get_mirror_source_port(struct switch_dev *dev,
|
||||
const struct switch_attr *attr,
|
||||
struct switch_val *val);
|
||||
int
|
||||
ar8xxx_sw_set_pvid(struct switch_dev *dev, int port, int vlan);
|
||||
int
|
||||
ar8xxx_sw_get_pvid(struct switch_dev *dev, int port, int *vlan);
|
||||
int
|
||||
ar8xxx_sw_hw_apply(struct switch_dev *dev);
|
||||
int
|
||||
ar8xxx_sw_reset_switch(struct switch_dev *dev);
|
||||
int
|
||||
ar8xxx_sw_get_port_link(struct switch_dev *dev, int port,
|
||||
struct switch_port_link *link);
|
||||
int
|
||||
ar8xxx_sw_set_port_reset_mib(struct switch_dev *dev,
|
||||
const struct switch_attr *attr,
|
||||
struct switch_val *val);
|
||||
int
|
||||
ar8xxx_sw_get_port_mib(struct switch_dev *dev,
|
||||
const struct switch_attr *attr,
|
||||
struct switch_val *val);
|
||||
int
|
||||
ar8xxx_sw_get_arl_age_time(struct switch_dev *dev,
|
||||
const struct switch_attr *attr,
|
||||
struct switch_val *val);
|
||||
int
|
||||
ar8xxx_sw_set_arl_age_time(struct switch_dev *dev,
|
||||
const struct switch_attr *attr,
|
||||
struct switch_val *val);
|
||||
int
|
||||
ar8xxx_sw_get_arl_table(struct switch_dev *dev,
|
||||
const struct switch_attr *attr,
|
||||
struct switch_val *val);
|
||||
int
|
||||
ar8xxx_sw_set_flush_arl_table(struct switch_dev *dev,
|
||||
const struct switch_attr *attr,
|
||||
struct switch_val *val);
|
||||
int
|
||||
ar8xxx_sw_set_flush_port_arl_table(struct switch_dev *dev,
|
||||
const struct switch_attr *attr,
|
||||
struct switch_val *val);
|
||||
int
|
||||
ar8xxx_sw_get_port_stats(struct switch_dev *dev, int port,
|
||||
struct switch_port_stats *stats);
|
||||
int
|
||||
ar8216_wait_bit(struct ar8xxx_priv *priv, int reg, u32 mask, u32 val);
|
||||
|
||||
static inline struct ar8xxx_priv *
|
||||
swdev_to_ar8xxx(struct switch_dev *swdev)
|
||||
{
|
||||
return container_of(swdev, struct ar8xxx_priv, dev);
|
||||
}
|
||||
|
||||
static inline bool ar8xxx_has_gige(struct ar8xxx_priv *priv)
|
||||
{
|
||||
return priv->chip->caps & AR8XXX_CAP_GIGE;
|
||||
}
|
||||
|
||||
static inline bool ar8xxx_has_mib_counters(struct ar8xxx_priv *priv)
|
||||
{
|
||||
return priv->chip->caps & AR8XXX_CAP_MIB_COUNTERS;
|
||||
}
|
||||
|
||||
static inline bool chip_is_ar8216(struct ar8xxx_priv *priv)
|
||||
{
|
||||
return priv->chip_ver == AR8XXX_VER_AR8216;
|
||||
}
|
||||
|
||||
static inline bool chip_is_ar8236(struct ar8xxx_priv *priv)
|
||||
{
|
||||
return priv->chip_ver == AR8XXX_VER_AR8236;
|
||||
}
|
||||
|
||||
static inline bool chip_is_ar8316(struct ar8xxx_priv *priv)
|
||||
{
|
||||
return priv->chip_ver == AR8XXX_VER_AR8316;
|
||||
}
|
||||
|
||||
static inline bool chip_is_ar8327(struct ar8xxx_priv *priv)
|
||||
{
|
||||
return priv->chip_ver == AR8XXX_VER_AR8327;
|
||||
}
|
||||
|
||||
static inline bool chip_is_ar8337(struct ar8xxx_priv *priv)
|
||||
{
|
||||
return priv->chip_ver == AR8XXX_VER_AR8337;
|
||||
}
|
||||
|
||||
static inline void
|
||||
ar8xxx_reg_set(struct ar8xxx_priv *priv, int reg, u32 val)
|
||||
{
|
||||
ar8xxx_rmw(priv, reg, 0, val);
|
||||
}
|
||||
|
||||
static inline void
|
||||
ar8xxx_reg_clear(struct ar8xxx_priv *priv, int reg, u32 val)
|
||||
{
|
||||
ar8xxx_rmw(priv, reg, val, 0);
|
||||
}
|
||||
|
||||
static inline void
|
||||
split_addr(u32 regaddr, u16 *r1, u16 *r2, u16 *page)
|
||||
{
|
||||
regaddr >>= 1;
|
||||
*r1 = regaddr & 0x1e;
|
||||
|
||||
regaddr >>= 5;
|
||||
*r2 = regaddr & 0x7;
|
||||
|
||||
regaddr >>= 3;
|
||||
*page = regaddr & 0x1ff;
|
||||
}
|
||||
|
||||
static inline void
|
||||
wait_for_page_switch(void)
|
||||
{
|
||||
udelay(5);
|
||||
}
|
||||
|
||||
#endif
|
1551
6.12/target/linux/generic/files/drivers/net/phy/ar8327.c
Normal file
1551
6.12/target/linux/generic/files/drivers/net/phy/ar8327.c
Normal file
File diff suppressed because it is too large
Load diff
333
6.12/target/linux/generic/files/drivers/net/phy/ar8327.h
Normal file
333
6.12/target/linux/generic/files/drivers/net/phy/ar8327.h
Normal file
|
@ -0,0 +1,333 @@
|
|||
/*
|
||||
* ar8327.h: AR8216 switch driver
|
||||
*
|
||||
* Copyright (C) 2009 Felix Fietkau <nbd@nbd.name>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#ifndef __AR8327_H
|
||||
#define __AR8327_H
|
||||
|
||||
#define AR8327_NUM_PORTS 7
|
||||
#define AR8327_NUM_LEDS 15
|
||||
#define AR8327_PORTS_ALL 0x7f
|
||||
#define AR8327_NUM_LED_CTRL_REGS 4
|
||||
|
||||
#define AR8327_REG_MASK 0x000
|
||||
|
||||
#define AR8327_REG_PAD0_MODE 0x004
|
||||
#define AR8327_REG_PAD5_MODE 0x008
|
||||
#define AR8327_REG_PAD6_MODE 0x00c
|
||||
#define AR8327_PAD_MAC_MII_RXCLK_SEL BIT(0)
|
||||
#define AR8327_PAD_MAC_MII_TXCLK_SEL BIT(1)
|
||||
#define AR8327_PAD_MAC_MII_EN BIT(2)
|
||||
#define AR8327_PAD_MAC_GMII_RXCLK_SEL BIT(4)
|
||||
#define AR8327_PAD_MAC_GMII_TXCLK_SEL BIT(5)
|
||||
#define AR8327_PAD_MAC_GMII_EN BIT(6)
|
||||
#define AR8327_PAD_SGMII_EN BIT(7)
|
||||
#define AR8327_PAD_PHY_MII_RXCLK_SEL BIT(8)
|
||||
#define AR8327_PAD_PHY_MII_TXCLK_SEL BIT(9)
|
||||
#define AR8327_PAD_PHY_MII_EN BIT(10)
|
||||
#define AR8327_PAD_PHY_GMII_PIPE_RXCLK_SEL BIT(11)
|
||||
#define AR8327_PAD_PHY_GMII_RXCLK_SEL BIT(12)
|
||||
#define AR8327_PAD_PHY_GMII_TXCLK_SEL BIT(13)
|
||||
#define AR8327_PAD_PHY_GMII_EN BIT(14)
|
||||
#define AR8327_PAD_PHYX_GMII_EN BIT(16)
|
||||
#define AR8327_PAD_PHYX_RGMII_EN BIT(17)
|
||||
#define AR8327_PAD_PHYX_MII_EN BIT(18)
|
||||
#define AR8327_PAD_SGMII_DELAY_EN BIT(19)
|
||||
#define AR8327_PAD_RGMII_RXCLK_DELAY_SEL BITS(20, 2)
|
||||
#define AR8327_PAD_RGMII_RXCLK_DELAY_SEL_S 20
|
||||
#define AR8327_PAD_RGMII_TXCLK_DELAY_SEL BITS(22, 2)
|
||||
#define AR8327_PAD_RGMII_TXCLK_DELAY_SEL_S 22
|
||||
#define AR8327_PAD_RGMII_RXCLK_DELAY_EN BIT(24)
|
||||
#define AR8327_PAD_RGMII_TXCLK_DELAY_EN BIT(25)
|
||||
#define AR8327_PAD_RGMII_EN BIT(26)
|
||||
|
||||
#define AR8327_REG_POWER_ON_STRAP 0x010
|
||||
#define AR8327_POWER_ON_STRAP_POWER_ON_SEL BIT(31)
|
||||
#define AR8327_POWER_ON_STRAP_LED_OPEN_EN BIT(24)
|
||||
#define AR8327_POWER_ON_STRAP_SERDES_AEN BIT(7)
|
||||
|
||||
#define AR8327_REG_INT_STATUS0 0x020
|
||||
#define AR8327_INT0_VT_DONE BIT(20)
|
||||
|
||||
#define AR8327_REG_INT_STATUS1 0x024
|
||||
#define AR8327_REG_INT_MASK0 0x028
|
||||
#define AR8327_REG_INT_MASK1 0x02c
|
||||
|
||||
#define AR8327_REG_MODULE_EN 0x030
|
||||
#define AR8327_MODULE_EN_MIB BIT(0)
|
||||
|
||||
#define AR8327_REG_MIB_FUNC 0x034
|
||||
#define AR8327_MIB_CPU_KEEP BIT(20)
|
||||
|
||||
#define AR8327_REG_SERVICE_TAG 0x048
|
||||
#define AR8327_REG_LED_CTRL(_i) (0x050 + (_i) * 4)
|
||||
#define AR8327_REG_LED_CTRL0 0x050
|
||||
#define AR8327_REG_LED_CTRL1 0x054
|
||||
#define AR8327_REG_LED_CTRL2 0x058
|
||||
#define AR8327_REG_LED_CTRL3 0x05c
|
||||
#define AR8327_REG_MAC_ADDR0 0x060
|
||||
#define AR8327_REG_MAC_ADDR1 0x064
|
||||
|
||||
#define AR8327_REG_MAX_FRAME_SIZE 0x078
|
||||
#define AR8327_MAX_FRAME_SIZE_MTU BITS(0, 14)
|
||||
|
||||
#define AR8327_REG_PORT_STATUS(_i) (0x07c + (_i) * 4)
|
||||
#define AR8327_PORT_STATUS_TXFLOW_AUTO BIT(10)
|
||||
#define AR8327_PORT_STATUS_RXFLOW_AUTO BIT(11)
|
||||
|
||||
#define AR8327_REG_HEADER_CTRL 0x098
|
||||
#define AR8327_REG_PORT_HEADER(_i) (0x09c + (_i) * 4)
|
||||
|
||||
#define AR8327_REG_SGMII_CTRL 0x0e0
|
||||
#define AR8327_SGMII_CTRL_EN_PLL BIT(1)
|
||||
#define AR8327_SGMII_CTRL_EN_RX BIT(2)
|
||||
#define AR8327_SGMII_CTRL_EN_TX BIT(3)
|
||||
|
||||
#define AR8327_REG_EEE_CTRL 0x100
|
||||
#define AR8327_EEE_CTRL_DISABLE_PHY(_i) BIT(4 + (_i) * 2)
|
||||
|
||||
#define AR8327_REG_FRAME_ACK_CTRL0 0x210
|
||||
#define AR8327_FRAME_ACK_CTRL_IGMP_MLD_EN0 BIT(0)
|
||||
#define AR8327_FRAME_ACK_CTRL_IGMP_JOIN_EN0 BIT(1)
|
||||
#define AR8327_FRAME_ACK_CTRL_IGMP_LEAVE_EN0 BIT(2)
|
||||
#define AR8327_FRAME_ACK_CTRL_EAPOL_EN0 BIT(3)
|
||||
#define AR8327_FRAME_ACK_CTRL_DHCP_EN0 BIT(4)
|
||||
#define AR8327_FRAME_ACK_CTRL_ARP_ACK_EN0 BIT(5)
|
||||
#define AR8327_FRAME_ACK_CTRL_ARP_REQ_EN0 BIT(6)
|
||||
#define AR8327_FRAME_ACK_CTRL_IGMP_MLD_EN1 BIT(8)
|
||||
#define AR8327_FRAME_ACK_CTRL_IGMP_JOIN_EN1 BIT(9)
|
||||
#define AR8327_FRAME_ACK_CTRL_IGMP_LEAVE_EN1 BIT(10)
|
||||
#define AR8327_FRAME_ACK_CTRL_EAPOL_EN1 BIT(11)
|
||||
#define AR8327_FRAME_ACK_CTRL_DHCP_EN1 BIT(12)
|
||||
#define AR8327_FRAME_ACK_CTRL_ARP_ACK_EN1 BIT(13)
|
||||
#define AR8327_FRAME_ACK_CTRL_ARP_REQ_EN1 BIT(14)
|
||||
#define AR8327_FRAME_ACK_CTRL_IGMP_MLD_EN2 BIT(16)
|
||||
#define AR8327_FRAME_ACK_CTRL_IGMP_JOIN_EN2 BIT(17)
|
||||
#define AR8327_FRAME_ACK_CTRL_IGMP_LEAVE_EN2 BIT(18)
|
||||
#define AR8327_FRAME_ACK_CTRL_EAPOL_EN2 BIT(19)
|
||||
#define AR8327_FRAME_ACK_CTRL_DHCP_EN2 BIT(20)
|
||||
#define AR8327_FRAME_ACK_CTRL_ARP_ACK_EN2 BIT(21)
|
||||
#define AR8327_FRAME_ACK_CTRL_ARP_REQ_EN2 BIT(22)
|
||||
#define AR8327_FRAME_ACK_CTRL_IGMP_MLD_EN3 BIT(24)
|
||||
#define AR8327_FRAME_ACK_CTRL_IGMP_JOIN_EN3 BIT(25)
|
||||
#define AR8327_FRAME_ACK_CTRL_IGMP_LEAVE_EN3 BIT(26)
|
||||
#define AR8327_FRAME_ACK_CTRL_EAPOL_EN3 BIT(27)
|
||||
#define AR8327_FRAME_ACK_CTRL_DHCP_EN3 BIT(28)
|
||||
#define AR8327_FRAME_ACK_CTRL_ARP_ACK_EN3 BIT(29)
|
||||
#define AR8327_FRAME_ACK_CTRL_ARP_REQ_EN3 BIT(30)
|
||||
|
||||
#define AR8327_REG_FRAME_ACK_CTRL1 0x214
|
||||
#define AR8327_FRAME_ACK_CTRL_IGMP_MLD_EN4 BIT(0)
|
||||
#define AR8327_FRAME_ACK_CTRL_IGMP_JOIN_EN4 BIT(1)
|
||||
#define AR8327_FRAME_ACK_CTRL_IGMP_LEAVE_EN4 BIT(2)
|
||||
#define AR8327_FRAME_ACK_CTRL_EAPOL_EN4 BIT(3)
|
||||
#define AR8327_FRAME_ACK_CTRL_DHCP_EN4 BIT(4)
|
||||
#define AR8327_FRAME_ACK_CTRL_ARP_ACK_EN4 BIT(5)
|
||||
#define AR8327_FRAME_ACK_CTRL_ARP_REQ_EN4 BIT(6)
|
||||
#define AR8327_FRAME_ACK_CTRL_IGMP_MLD_EN5 BIT(8)
|
||||
#define AR8327_FRAME_ACK_CTRL_IGMP_JOIN_EN5 BIT(9)
|
||||
#define AR8327_FRAME_ACK_CTRL_IGMP_LEAVE_EN5 BIT(10)
|
||||
#define AR8327_FRAME_ACK_CTRL_EAPOL_EN5 BIT(11)
|
||||
#define AR8327_FRAME_ACK_CTRL_DHCP_EN5 BIT(12)
|
||||
#define AR8327_FRAME_ACK_CTRL_ARP_ACK_EN5 BIT(13)
|
||||
#define AR8327_FRAME_ACK_CTRL_ARP_REQ_EN5 BIT(14)
|
||||
#define AR8327_FRAME_ACK_CTRL_IGMP_MLD_EN6 BIT(16)
|
||||
#define AR8327_FRAME_ACK_CTRL_IGMP_JOIN_EN6 BIT(17)
|
||||
#define AR8327_FRAME_ACK_CTRL_IGMP_LEAVE_EN6 BIT(18)
|
||||
#define AR8327_FRAME_ACK_CTRL_EAPOL_EN6 BIT(19)
|
||||
#define AR8327_FRAME_ACK_CTRL_DHCP_EN6 BIT(20)
|
||||
#define AR8327_FRAME_ACK_CTRL_ARP_ACK_EN6 BIT(21)
|
||||
#define AR8327_FRAME_ACK_CTRL_ARP_REQ_EN6 BIT(22)
|
||||
#define AR8327_FRAME_ACK_CTRL_IGMP_V3_EN BIT(24)
|
||||
#define AR8327_FRAME_ACK_CTRL_PPPOE_EN BIT(25)
|
||||
|
||||
#define AR8327_REG_FRAME_ACK_CTRL(_i) (0x210 + ((_i) / 4) * 0x4)
|
||||
#define AR8327_FRAME_ACK_CTRL_IGMP_MLD BIT(0)
|
||||
#define AR8327_FRAME_ACK_CTRL_IGMP_JOIN BIT(1)
|
||||
#define AR8327_FRAME_ACK_CTRL_IGMP_LEAVE BIT(2)
|
||||
#define AR8327_FRAME_ACK_CTRL_EAPOL BIT(3)
|
||||
#define AR8327_FRAME_ACK_CTRL_DHCP BIT(4)
|
||||
#define AR8327_FRAME_ACK_CTRL_ARP_ACK BIT(5)
|
||||
#define AR8327_FRAME_ACK_CTRL_ARP_REQ BIT(6)
|
||||
#define AR8327_FRAME_ACK_CTRL_S(_i) (((_i) % 4) * 8)
|
||||
|
||||
#define AR8327_REG_PORT_VLAN0(_i) (0x420 + (_i) * 0x8)
|
||||
#define AR8327_PORT_VLAN0_DEF_PRI_MASK BITS(0, 3)
|
||||
#define AR8327_PORT_VLAN0_DEF_SVID BITS(0, 12)
|
||||
#define AR8327_PORT_VLAN0_DEF_SVID_S 0
|
||||
#define AR8327_PORT_VLAN0_DEF_SPRI BITS(13, 3)
|
||||
#define AR8327_PORT_VLAN0_DEF_SPRI_S 13
|
||||
#define AR8327_PORT_VLAN0_DEF_CVID BITS(16, 12)
|
||||
#define AR8327_PORT_VLAN0_DEF_CVID_S 16
|
||||
#define AR8327_PORT_VLAN0_DEF_CPRI BITS(29, 3)
|
||||
#define AR8327_PORT_VLAN0_DEF_CPRI_S 29
|
||||
|
||||
#define AR8327_REG_PORT_VLAN1(_i) (0x424 + (_i) * 0x8)
|
||||
#define AR8327_PORT_VLAN1_VLAN_PRI_PROP BIT(4)
|
||||
#define AR8327_PORT_VLAN1_PORT_VLAN_PROP BIT(6)
|
||||
#define AR8327_PORT_VLAN1_OUT_MODE BITS(12, 2)
|
||||
#define AR8327_PORT_VLAN1_OUT_MODE_S 12
|
||||
#define AR8327_PORT_VLAN1_OUT_MODE_UNMOD 0
|
||||
#define AR8327_PORT_VLAN1_OUT_MODE_UNTAG 1
|
||||
#define AR8327_PORT_VLAN1_OUT_MODE_TAG 2
|
||||
#define AR8327_PORT_VLAN1_OUT_MODE_UNTOUCH 3
|
||||
|
||||
#define AR8327_REG_ATU_DATA0 0x600
|
||||
#define AR8327_ATU_ADDR0 BITS(0, 8)
|
||||
#define AR8327_ATU_ADDR0_S 0
|
||||
#define AR8327_ATU_ADDR1 BITS(8, 8)
|
||||
#define AR8327_ATU_ADDR1_S 8
|
||||
#define AR8327_ATU_ADDR2 BITS(16, 8)
|
||||
#define AR8327_ATU_ADDR2_S 16
|
||||
#define AR8327_ATU_ADDR3 BITS(24, 8)
|
||||
#define AR8327_ATU_ADDR3_S 24
|
||||
#define AR8327_REG_ATU_DATA1 0x604
|
||||
#define AR8327_ATU_ADDR4 BITS(0, 8)
|
||||
#define AR8327_ATU_ADDR4_S 0
|
||||
#define AR8327_ATU_ADDR5 BITS(8, 8)
|
||||
#define AR8327_ATU_ADDR5_S 8
|
||||
#define AR8327_ATU_PORTS BITS(16, 7)
|
||||
#define AR8327_ATU_PORTS_S 16
|
||||
#define AR8327_ATU_PORT0 BIT(16)
|
||||
#define AR8327_ATU_PORT1 BIT(17)
|
||||
#define AR8327_ATU_PORT2 BIT(18)
|
||||
#define AR8327_ATU_PORT3 BIT(19)
|
||||
#define AR8327_ATU_PORT4 BIT(20)
|
||||
#define AR8327_ATU_PORT5 BIT(21)
|
||||
#define AR8327_ATU_PORT6 BIT(22)
|
||||
#define AR8327_REG_ATU_DATA2 0x608
|
||||
#define AR8327_ATU_STATUS BITS(0, 4)
|
||||
|
||||
#define AR8327_REG_ATU_FUNC 0x60c
|
||||
#define AR8327_ATU_FUNC_OP BITS(0, 4)
|
||||
#define AR8327_ATU_FUNC_OP_NOOP 0x0
|
||||
#define AR8327_ATU_FUNC_OP_FLUSH 0x1
|
||||
#define AR8327_ATU_FUNC_OP_LOAD 0x2
|
||||
#define AR8327_ATU_FUNC_OP_PURGE 0x3
|
||||
#define AR8327_ATU_FUNC_OP_FLUSH_UNLOCKED 0x4
|
||||
#define AR8327_ATU_FUNC_OP_FLUSH_PORT 0x5
|
||||
#define AR8327_ATU_FUNC_OP_GET_NEXT 0x6
|
||||
#define AR8327_ATU_FUNC_OP_SEARCH_MAC 0x7
|
||||
#define AR8327_ATU_FUNC_OP_CHANGE_TRUNK 0x8
|
||||
#define AR8327_ATU_PORT_NUM BITS(8, 4)
|
||||
#define AR8327_ATU_PORT_NUM_S 8
|
||||
#define AR8327_ATU_FUNC_BUSY BIT(31)
|
||||
|
||||
#define AR8327_REG_VTU_FUNC0 0x0610
|
||||
#define AR8327_VTU_FUNC0_EG_MODE BITS(4, 14)
|
||||
#define AR8327_VTU_FUNC0_EG_MODE_S(_i) (4 + (_i) * 2)
|
||||
#define AR8327_VTU_FUNC0_EG_MODE_KEEP 0
|
||||
#define AR8327_VTU_FUNC0_EG_MODE_UNTAG 1
|
||||
#define AR8327_VTU_FUNC0_EG_MODE_TAG 2
|
||||
#define AR8327_VTU_FUNC0_EG_MODE_NOT 3
|
||||
#define AR8327_VTU_FUNC0_IVL BIT(19)
|
||||
#define AR8327_VTU_FUNC0_VALID BIT(20)
|
||||
|
||||
#define AR8327_REG_VTU_FUNC1 0x0614
|
||||
#define AR8327_VTU_FUNC1_OP BITS(0, 3)
|
||||
#define AR8327_VTU_FUNC1_OP_NOOP 0
|
||||
#define AR8327_VTU_FUNC1_OP_FLUSH 1
|
||||
#define AR8327_VTU_FUNC1_OP_LOAD 2
|
||||
#define AR8327_VTU_FUNC1_OP_PURGE 3
|
||||
#define AR8327_VTU_FUNC1_OP_REMOVE_PORT 4
|
||||
#define AR8327_VTU_FUNC1_OP_GET_NEXT 5
|
||||
#define AR8327_VTU_FUNC1_OP_GET_ONE 6
|
||||
#define AR8327_VTU_FUNC1_FULL BIT(4)
|
||||
#define AR8327_VTU_FUNC1_PORT BIT(8, 4)
|
||||
#define AR8327_VTU_FUNC1_PORT_S 8
|
||||
#define AR8327_VTU_FUNC1_VID BIT(16, 12)
|
||||
#define AR8327_VTU_FUNC1_VID_S 16
|
||||
#define AR8327_VTU_FUNC1_BUSY BIT(31)
|
||||
|
||||
#define AR8327_REG_ARL_CTRL 0x0618
|
||||
|
||||
#define AR8327_REG_FWD_CTRL0 0x620
|
||||
#define AR8327_FWD_CTRL0_CPU_PORT_EN BIT(10)
|
||||
#define AR8327_FWD_CTRL0_MIRROR_PORT BITS(4, 4)
|
||||
#define AR8327_FWD_CTRL0_MIRROR_PORT_S 4
|
||||
|
||||
#define AR8327_REG_FWD_CTRL1 0x624
|
||||
#define AR8327_FWD_CTRL1_UC_FLOOD BITS(0, 7)
|
||||
#define AR8327_FWD_CTRL1_UC_FLOOD_S 0
|
||||
#define AR8327_FWD_CTRL1_MC_FLOOD BITS(8, 7)
|
||||
#define AR8327_FWD_CTRL1_MC_FLOOD_S 8
|
||||
#define AR8327_FWD_CTRL1_BC_FLOOD BITS(16, 7)
|
||||
#define AR8327_FWD_CTRL1_BC_FLOOD_S 16
|
||||
#define AR8327_FWD_CTRL1_IGMP BITS(24, 7)
|
||||
#define AR8327_FWD_CTRL1_IGMP_S 24
|
||||
|
||||
#define AR8327_REG_PORT_LOOKUP(_i) (0x660 + (_i) * 0xc)
|
||||
#define AR8327_PORT_LOOKUP_MEMBER BITS(0, 7)
|
||||
#define AR8327_PORT_LOOKUP_IN_MODE BITS(8, 2)
|
||||
#define AR8327_PORT_LOOKUP_IN_MODE_S 8
|
||||
#define AR8327_PORT_LOOKUP_STATE BITS(16, 3)
|
||||
#define AR8327_PORT_LOOKUP_STATE_S 16
|
||||
#define AR8327_PORT_LOOKUP_LEARN BIT(20)
|
||||
#define AR8327_PORT_LOOKUP_ING_MIRROR_EN BIT(25)
|
||||
|
||||
#define AR8327_REG_PORT_PRIO(_i) (0x664 + (_i) * 0xc)
|
||||
|
||||
#define AR8327_REG_PORT_HOL_CTRL1(_i) (0x974 + (_i) * 0x8)
|
||||
#define AR8327_PORT_HOL_CTRL1_EG_MIRROR_EN BIT(16)
|
||||
|
||||
#define AR8337_PAD_MAC06_EXCHANGE_EN BIT(31)
|
||||
|
||||
#define AR8327_PHY_MODE_SEL 0x12
|
||||
#define AR8327_PHY_MODE_SEL_RGMII BIT(3)
|
||||
#define AR8327_PHY_TEST_CTRL 0x0
|
||||
#define AR8327_PHY_TEST_CTRL_RGMII_RX_DELAY BIT(15)
|
||||
#define AR8327_PHY_SYS_CTRL 0x5
|
||||
#define AR8327_PHY_SYS_CTRL_RGMII_TX_DELAY BIT(8)
|
||||
|
||||
enum ar8327_led_pattern {
|
||||
AR8327_LED_PATTERN_OFF = 0,
|
||||
AR8327_LED_PATTERN_BLINK,
|
||||
AR8327_LED_PATTERN_ON,
|
||||
AR8327_LED_PATTERN_RULE,
|
||||
};
|
||||
|
||||
struct ar8327_led_entry {
|
||||
unsigned reg;
|
||||
unsigned shift;
|
||||
};
|
||||
|
||||
struct ar8327_led {
|
||||
struct led_classdev cdev;
|
||||
struct ar8xxx_priv *sw_priv;
|
||||
|
||||
char *name;
|
||||
bool active_low;
|
||||
u8 led_num;
|
||||
enum ar8327_led_mode mode;
|
||||
|
||||
struct mutex mutex;
|
||||
spinlock_t lock;
|
||||
struct work_struct led_work;
|
||||
bool enable_hw_mode;
|
||||
enum ar8327_led_pattern pattern;
|
||||
};
|
||||
|
||||
struct ar8327_data {
|
||||
u32 port0_status;
|
||||
u32 port6_status;
|
||||
|
||||
struct ar8327_led **leds;
|
||||
unsigned int num_leds;
|
||||
|
||||
/* all fields below are cleared on reset */
|
||||
bool eee[AR8XXX_NUM_PHYS];
|
||||
};
|
||||
|
||||
#endif
|
37
6.12/target/linux/generic/files/drivers/net/phy/b53/Kconfig
Normal file
37
6.12/target/linux/generic/files/drivers/net/phy/b53/Kconfig
Normal file
|
@ -0,0 +1,37 @@
|
|||
menuconfig SWCONFIG_B53
|
||||
tristate "Broadcom bcm53xx managed switch support"
|
||||
depends on SWCONFIG
|
||||
help
|
||||
This driver adds support for Broadcom managed switch chips. It supports
|
||||
BCM5325E, BCM5365, BCM539x, BCM53115 and BCM53125 as well as BCM63XX
|
||||
integrated switches.
|
||||
|
||||
config SWCONFIG_B53_SPI_DRIVER
|
||||
tristate "B53 SPI connected switch driver"
|
||||
depends on SWCONFIG_B53 && SPI
|
||||
help
|
||||
Select to enable support for registering switches configured through SPI.
|
||||
|
||||
config SWCONFIG_B53_PHY_DRIVER
|
||||
tristate "B53 MDIO connected switch driver"
|
||||
depends on SWCONFIG_B53
|
||||
select SWCONFIG_B53_PHY_FIXUP
|
||||
help
|
||||
Select to enable support for registering switches configured through MDIO.
|
||||
|
||||
config SWCONFIG_B53_MMAP_DRIVER
|
||||
tristate "B53 MMAP connected switch driver"
|
||||
depends on SWCONFIG_B53
|
||||
help
|
||||
Select to enable support for memory-mapped switches like the BCM63XX
|
||||
integrated switches.
|
||||
|
||||
config SWCONFIG_B53_SRAB_DRIVER
|
||||
tristate "B53 SRAB connected switch driver"
|
||||
depends on SWCONFIG_B53
|
||||
help
|
||||
Select to enable support for memory-mapped Switch Register Access
|
||||
Bridge Registers (SRAB) like it is found on the BCM53010
|
||||
|
||||
config SWCONFIG_B53_PHY_FIXUP
|
||||
bool
|
10
6.12/target/linux/generic/files/drivers/net/phy/b53/Makefile
Normal file
10
6.12/target/linux/generic/files/drivers/net/phy/b53/Makefile
Normal file
|
@ -0,0 +1,10 @@
|
|||
obj-$(CONFIG_SWCONFIG_B53) += b53_common.o
|
||||
|
||||
obj-$(CONFIG_SWCONFIG_B53_PHY_FIXUP) += b53_phy_fixup.o
|
||||
|
||||
obj-$(CONFIG_SWCONFIG_B53_MMAP_DRIVER) += b53_mmap.o
|
||||
obj-$(CONFIG_SWCONFIG_B53_SRAB_DRIVER) += b53_srab.o
|
||||
obj-$(CONFIG_SWCONFIG_B53_PHY_DRIVER) += b53_mdio.o
|
||||
obj-$(CONFIG_SWCONFIG_B53_SPI_DRIVER) += b53_spi.o
|
||||
|
||||
ccflags-y += -Werror
|
1724
6.12/target/linux/generic/files/drivers/net/phy/b53/b53_common.c
Normal file
1724
6.12/target/linux/generic/files/drivers/net/phy/b53/b53_common.c
Normal file
File diff suppressed because it is too large
Load diff
436
6.12/target/linux/generic/files/drivers/net/phy/b53/b53_mdio.c
Normal file
436
6.12/target/linux/generic/files/drivers/net/phy/b53/b53_mdio.c
Normal file
|
@ -0,0 +1,436 @@
|
|||
/*
|
||||
* B53 register access through MII registers
|
||||
*
|
||||
* Copyright (C) 2011-2013 Jonas Gorski <jogo@openwrt.org>
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/phy.h>
|
||||
#include <linux/module.h>
|
||||
|
||||
#include "b53_priv.h"
|
||||
|
||||
#define B53_PSEUDO_PHY 0x1e /* Register Access Pseudo PHY */
|
||||
|
||||
/* MII registers */
|
||||
#define REG_MII_PAGE 0x10 /* MII Page register */
|
||||
#define REG_MII_ADDR 0x11 /* MII Address register */
|
||||
#define REG_MII_DATA0 0x18 /* MII Data register 0 */
|
||||
#define REG_MII_DATA1 0x19 /* MII Data register 1 */
|
||||
#define REG_MII_DATA2 0x1a /* MII Data register 2 */
|
||||
#define REG_MII_DATA3 0x1b /* MII Data register 3 */
|
||||
|
||||
#define REG_MII_PAGE_ENABLE BIT(0)
|
||||
#define REG_MII_ADDR_WRITE BIT(0)
|
||||
#define REG_MII_ADDR_READ BIT(1)
|
||||
|
||||
static int b53_mdio_op(struct b53_device *dev, u8 page, u8 reg, u16 op)
|
||||
{
|
||||
int i;
|
||||
u16 v;
|
||||
int ret;
|
||||
struct mii_bus *bus = dev->priv;
|
||||
|
||||
if (dev->current_page != page) {
|
||||
/* set page number */
|
||||
v = (page << 8) | REG_MII_PAGE_ENABLE;
|
||||
ret = mdiobus_write(bus, B53_PSEUDO_PHY, REG_MII_PAGE, v);
|
||||
if (ret)
|
||||
return ret;
|
||||
dev->current_page = page;
|
||||
}
|
||||
|
||||
/* set register address */
|
||||
v = (reg << 8) | op;
|
||||
ret = mdiobus_write(bus, B53_PSEUDO_PHY, REG_MII_ADDR, v);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* check if operation completed */
|
||||
for (i = 0; i < 5; ++i) {
|
||||
v = mdiobus_read(bus, B53_PSEUDO_PHY, REG_MII_ADDR);
|
||||
if (!(v & (REG_MII_ADDR_WRITE | REG_MII_ADDR_READ)))
|
||||
break;
|
||||
usleep_range(10, 100);
|
||||
}
|
||||
|
||||
if (WARN_ON(i == 5))
|
||||
return -EIO;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int b53_mdio_read8(struct b53_device *dev, u8 page, u8 reg, u8 *val)
|
||||
{
|
||||
struct mii_bus *bus = dev->priv;
|
||||
int ret;
|
||||
|
||||
ret = b53_mdio_op(dev, page, reg, REG_MII_ADDR_READ);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
*val = mdiobus_read(bus, B53_PSEUDO_PHY, REG_MII_DATA0) & 0xff;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int b53_mdio_read16(struct b53_device *dev, u8 page, u8 reg, u16 *val)
|
||||
{
|
||||
struct mii_bus *bus = dev->priv;
|
||||
int ret;
|
||||
|
||||
ret = b53_mdio_op(dev, page, reg, REG_MII_ADDR_READ);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
*val = mdiobus_read(bus, B53_PSEUDO_PHY, REG_MII_DATA0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int b53_mdio_read32(struct b53_device *dev, u8 page, u8 reg, u32 *val)
|
||||
{
|
||||
struct mii_bus *bus = dev->priv;
|
||||
int ret;
|
||||
|
||||
ret = b53_mdio_op(dev, page, reg, REG_MII_ADDR_READ);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
*val = mdiobus_read(bus, B53_PSEUDO_PHY, REG_MII_DATA0);
|
||||
*val |= mdiobus_read(bus, B53_PSEUDO_PHY, REG_MII_DATA1) << 16;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int b53_mdio_read48(struct b53_device *dev, u8 page, u8 reg, u64 *val)
|
||||
{
|
||||
struct mii_bus *bus = dev->priv;
|
||||
u64 temp = 0;
|
||||
int i;
|
||||
int ret;
|
||||
|
||||
ret = b53_mdio_op(dev, page, reg, REG_MII_ADDR_READ);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
for (i = 2; i >= 0; i--) {
|
||||
temp <<= 16;
|
||||
temp |= mdiobus_read(bus, B53_PSEUDO_PHY, REG_MII_DATA0 + i);
|
||||
}
|
||||
|
||||
*val = temp;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int b53_mdio_read64(struct b53_device *dev, u8 page, u8 reg, u64 *val)
|
||||
{
|
||||
struct mii_bus *bus = dev->priv;
|
||||
u64 temp = 0;
|
||||
int i;
|
||||
int ret;
|
||||
|
||||
ret = b53_mdio_op(dev, page, reg, REG_MII_ADDR_READ);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
for (i = 3; i >= 0; i--) {
|
||||
temp <<= 16;
|
||||
temp |= mdiobus_read(bus, B53_PSEUDO_PHY, REG_MII_DATA0 + i);
|
||||
}
|
||||
|
||||
*val = temp;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int b53_mdio_write8(struct b53_device *dev, u8 page, u8 reg, u8 value)
|
||||
{
|
||||
struct mii_bus *bus = dev->priv;
|
||||
int ret;
|
||||
|
||||
ret = mdiobus_write(bus, B53_PSEUDO_PHY, REG_MII_DATA0, value);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return b53_mdio_op(dev, page, reg, REG_MII_ADDR_WRITE);
|
||||
}
|
||||
|
||||
static int b53_mdio_write16(struct b53_device *dev, u8 page, u8 reg,
|
||||
u16 value)
|
||||
{
|
||||
struct mii_bus *bus = dev->priv;
|
||||
int ret;
|
||||
|
||||
ret = mdiobus_write(bus, B53_PSEUDO_PHY, REG_MII_DATA0, value);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return b53_mdio_op(dev, page, reg, REG_MII_ADDR_WRITE);
|
||||
}
|
||||
|
||||
static int b53_mdio_write32(struct b53_device *dev, u8 page, u8 reg,
|
||||
u32 value)
|
||||
{
|
||||
struct mii_bus *bus = dev->priv;
|
||||
unsigned int i;
|
||||
u32 temp = value;
|
||||
|
||||
for (i = 0; i < 2; i++) {
|
||||
int ret = mdiobus_write(bus, B53_PSEUDO_PHY, REG_MII_DATA0 + i,
|
||||
temp & 0xffff);
|
||||
if (ret)
|
||||
return ret;
|
||||
temp >>= 16;
|
||||
}
|
||||
|
||||
return b53_mdio_op(dev, page, reg, REG_MII_ADDR_WRITE);
|
||||
|
||||
}
|
||||
|
||||
static int b53_mdio_write48(struct b53_device *dev, u8 page, u8 reg,
|
||||
u64 value)
|
||||
{
|
||||
struct mii_bus *bus = dev->priv;
|
||||
unsigned i;
|
||||
u64 temp = value;
|
||||
|
||||
for (i = 0; i < 3; i++) {
|
||||
int ret = mdiobus_write(bus, B53_PSEUDO_PHY, REG_MII_DATA0 + i,
|
||||
temp & 0xffff);
|
||||
if (ret)
|
||||
return ret;
|
||||
temp >>= 16;
|
||||
}
|
||||
|
||||
return b53_mdio_op(dev, page, reg, REG_MII_ADDR_WRITE);
|
||||
|
||||
}
|
||||
|
||||
static int b53_mdio_write64(struct b53_device *dev, u8 page, u8 reg,
|
||||
u64 value)
|
||||
{
|
||||
struct mii_bus *bus = dev->priv;
|
||||
unsigned i;
|
||||
u64 temp = value;
|
||||
|
||||
for (i = 0; i < 4; i++) {
|
||||
int ret = mdiobus_write(bus, B53_PSEUDO_PHY, REG_MII_DATA0 + i,
|
||||
temp & 0xffff);
|
||||
if (ret)
|
||||
return ret;
|
||||
temp >>= 16;
|
||||
}
|
||||
|
||||
return b53_mdio_op(dev, page, reg, REG_MII_ADDR_WRITE);
|
||||
}
|
||||
|
||||
static int b53_mdio_phy_read16(struct b53_device *dev, int addr, u8 reg,
|
||||
u16 *value)
|
||||
{
|
||||
struct mii_bus *bus = dev->priv;
|
||||
|
||||
*value = mdiobus_read(bus, addr, reg);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int b53_mdio_phy_write16(struct b53_device *dev, int addr, u8 reg,
|
||||
u16 value)
|
||||
{
|
||||
struct mii_bus *bus = dev->priv;
|
||||
|
||||
return mdiobus_write(bus, addr, reg, value);
|
||||
}
|
||||
|
||||
static struct b53_io_ops b53_mdio_ops = {
|
||||
.read8 = b53_mdio_read8,
|
||||
.read16 = b53_mdio_read16,
|
||||
.read32 = b53_mdio_read32,
|
||||
.read48 = b53_mdio_read48,
|
||||
.read64 = b53_mdio_read64,
|
||||
.write8 = b53_mdio_write8,
|
||||
.write16 = b53_mdio_write16,
|
||||
.write32 = b53_mdio_write32,
|
||||
.write48 = b53_mdio_write48,
|
||||
.write64 = b53_mdio_write64,
|
||||
.phy_read16 = b53_mdio_phy_read16,
|
||||
.phy_write16 = b53_mdio_phy_write16,
|
||||
};
|
||||
|
||||
static int b53_phy_probe(struct phy_device *phydev)
|
||||
{
|
||||
struct b53_device *dev;
|
||||
int ret;
|
||||
|
||||
/* allow the generic phy driver to take over */
|
||||
if (phydev->mdio.addr != B53_PSEUDO_PHY && phydev->mdio.addr != 0)
|
||||
return -ENODEV;
|
||||
|
||||
dev = b53_swconfig_switch_alloc(&phydev->mdio.dev, &b53_mdio_ops, phydev->mdio.bus);
|
||||
if (!dev)
|
||||
return -ENOMEM;
|
||||
|
||||
dev->current_page = 0xff;
|
||||
dev->priv = phydev->mdio.bus;
|
||||
dev->ops = &b53_mdio_ops;
|
||||
dev->pdata = NULL;
|
||||
mutex_init(&dev->reg_mutex);
|
||||
|
||||
ret = b53_swconfig_switch_detect(dev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
linkmode_zero(phydev->supported);
|
||||
if (is5325(dev) || is5365(dev))
|
||||
linkmode_set_bit(ETHTOOL_LINK_MODE_100baseT_Full_BIT, phydev->supported);
|
||||
else
|
||||
linkmode_set_bit(ETHTOOL_LINK_MODE_1000baseT_Full_BIT, phydev->supported);
|
||||
|
||||
linkmode_copy(phydev->advertising, phydev->supported);
|
||||
|
||||
ret = b53_swconfig_switch_register(dev);
|
||||
if (ret) {
|
||||
dev_err(dev->dev, "failed to register switch: %i\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
phydev->priv = dev;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int b53_phy_config_init(struct phy_device *phydev)
|
||||
{
|
||||
struct b53_device *dev = phydev->priv;
|
||||
|
||||
/* we don't use page 0xff, so force a page set */
|
||||
dev->current_page = 0xff;
|
||||
/* force the ethX as alias */
|
||||
dev->sw_dev.alias = phydev->attached_dev->name;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void b53_phy_remove(struct phy_device *phydev)
|
||||
{
|
||||
struct b53_device *priv = phydev->priv;
|
||||
|
||||
if (!priv)
|
||||
return;
|
||||
|
||||
b53_switch_remove(priv);
|
||||
|
||||
phydev->priv = NULL;
|
||||
}
|
||||
|
||||
static int b53_phy_config_aneg(struct phy_device *phydev)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int b53_phy_read_status(struct phy_device *phydev)
|
||||
{
|
||||
struct b53_device *priv = phydev->priv;
|
||||
|
||||
if (is5325(priv) || is5365(priv))
|
||||
phydev->speed = 100;
|
||||
else
|
||||
phydev->speed = 1000;
|
||||
|
||||
phydev->duplex = DUPLEX_FULL;
|
||||
phydev->link = 1;
|
||||
phydev->state = PHY_RUNNING;
|
||||
|
||||
netif_carrier_on(phydev->attached_dev);
|
||||
phydev->adjust_link(phydev->attached_dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* BCM5325, BCM539x */
|
||||
static struct phy_driver b53_phy_driver_id1 = {
|
||||
.phy_id = 0x0143bc00,
|
||||
.name = "Broadcom B53 (1)",
|
||||
.phy_id_mask = 0x1ffffc00,
|
||||
.features = 0,
|
||||
.probe = b53_phy_probe,
|
||||
.remove = b53_phy_remove,
|
||||
.config_aneg = b53_phy_config_aneg,
|
||||
.config_init = b53_phy_config_init,
|
||||
.read_status = b53_phy_read_status,
|
||||
};
|
||||
|
||||
/* BCM53125, BCM53128 */
|
||||
static struct phy_driver b53_phy_driver_id2 = {
|
||||
.phy_id = 0x03625c00,
|
||||
.name = "Broadcom B53 (2)",
|
||||
.phy_id_mask = 0x1ffffc00,
|
||||
.features = 0,
|
||||
.probe = b53_phy_probe,
|
||||
.remove = b53_phy_remove,
|
||||
.config_aneg = b53_phy_config_aneg,
|
||||
.config_init = b53_phy_config_init,
|
||||
.read_status = b53_phy_read_status,
|
||||
};
|
||||
|
||||
/* BCM5365 */
|
||||
static struct phy_driver b53_phy_driver_id3 = {
|
||||
.phy_id = 0x00406300,
|
||||
.name = "Broadcom B53 (3)",
|
||||
.phy_id_mask = 0x1fffff00,
|
||||
.features = 0,
|
||||
.probe = b53_phy_probe,
|
||||
.remove = b53_phy_remove,
|
||||
.config_aneg = b53_phy_config_aneg,
|
||||
.config_init = b53_phy_config_init,
|
||||
.read_status = b53_phy_read_status,
|
||||
};
|
||||
|
||||
int __init b53_phy_driver_register(void)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = phy_driver_register(&b53_phy_driver_id1, THIS_MODULE);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = phy_driver_register(&b53_phy_driver_id2, THIS_MODULE);
|
||||
if (ret)
|
||||
goto err1;
|
||||
|
||||
ret = phy_driver_register(&b53_phy_driver_id3, THIS_MODULE);
|
||||
if (!ret)
|
||||
return 0;
|
||||
|
||||
phy_driver_unregister(&b53_phy_driver_id2);
|
||||
err1:
|
||||
phy_driver_unregister(&b53_phy_driver_id1);
|
||||
return ret;
|
||||
}
|
||||
|
||||
void __exit b53_phy_driver_unregister(void)
|
||||
{
|
||||
phy_driver_unregister(&b53_phy_driver_id3);
|
||||
phy_driver_unregister(&b53_phy_driver_id2);
|
||||
phy_driver_unregister(&b53_phy_driver_id1);
|
||||
}
|
||||
|
||||
module_init(b53_phy_driver_register);
|
||||
module_exit(b53_phy_driver_unregister);
|
||||
|
||||
MODULE_DESCRIPTION("B53 MDIO access driver");
|
||||
MODULE_LICENSE("Dual BSD/GPL");
|
248
6.12/target/linux/generic/files/drivers/net/phy/b53/b53_mmap.c
Normal file
248
6.12/target/linux/generic/files/drivers/net/phy/b53/b53_mmap.c
Normal file
|
@ -0,0 +1,248 @@
|
|||
/*
|
||||
* B53 register access through memory mapped registers
|
||||
*
|
||||
* Copyright (C) 2012-2013 Jonas Gorski <jogo@openwrt.org>
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/platform_data/b53.h>
|
||||
#include <linux/version.h>
|
||||
|
||||
#include "b53_priv.h"
|
||||
|
||||
static int b53_mmap_read8(struct b53_device *dev, u8 page, u8 reg, u8 *val)
|
||||
{
|
||||
u8 __iomem *regs = dev->priv;
|
||||
|
||||
*val = readb(regs + (page << 8) + reg);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int b53_mmap_read16(struct b53_device *dev, u8 page, u8 reg, u16 *val)
|
||||
{
|
||||
u8 __iomem *regs = dev->priv;
|
||||
|
||||
if (WARN_ON(reg % 2))
|
||||
return -EINVAL;
|
||||
|
||||
if (dev->pdata && dev->pdata->big_endian)
|
||||
*val = readw_be(regs + (page << 8) + reg);
|
||||
else
|
||||
*val = readw(regs + (page << 8) + reg);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int b53_mmap_read32(struct b53_device *dev, u8 page, u8 reg, u32 *val)
|
||||
{
|
||||
u8 __iomem *regs = dev->priv;
|
||||
|
||||
if (WARN_ON(reg % 4))
|
||||
return -EINVAL;
|
||||
|
||||
if (dev->pdata && dev->pdata->big_endian)
|
||||
*val = readl_be(regs + (page << 8) + reg);
|
||||
else
|
||||
*val = readl(regs + (page << 8) + reg);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int b53_mmap_read48(struct b53_device *dev, u8 page, u8 reg, u64 *val)
|
||||
{
|
||||
if (WARN_ON(reg % 2))
|
||||
return -EINVAL;
|
||||
|
||||
if (reg % 4) {
|
||||
u16 lo;
|
||||
u32 hi;
|
||||
|
||||
b53_mmap_read16(dev, page, reg, &lo);
|
||||
b53_mmap_read32(dev, page, reg + 2, &hi);
|
||||
|
||||
*val = ((u64)hi << 16) | lo;
|
||||
} else {
|
||||
u32 lo;
|
||||
u16 hi;
|
||||
|
||||
b53_mmap_read32(dev, page, reg, &lo);
|
||||
b53_mmap_read16(dev, page, reg + 4, &hi);
|
||||
|
||||
*val = ((u64)hi << 32) | lo;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int b53_mmap_read64(struct b53_device *dev, u8 page, u8 reg, u64 *val)
|
||||
{
|
||||
u32 hi, lo;
|
||||
|
||||
if (WARN_ON(reg % 4))
|
||||
return -EINVAL;
|
||||
|
||||
b53_mmap_read32(dev, page, reg, &lo);
|
||||
b53_mmap_read32(dev, page, reg + 4, &hi);
|
||||
|
||||
*val = ((u64)hi << 32) | lo;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int b53_mmap_write8(struct b53_device *dev, u8 page, u8 reg, u8 value)
|
||||
{
|
||||
u8 __iomem *regs = dev->priv;
|
||||
|
||||
writeb(value, regs + (page << 8) + reg);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int b53_mmap_write16(struct b53_device *dev, u8 page, u8 reg,
|
||||
u16 value)
|
||||
{
|
||||
u8 __iomem *regs = dev->priv;
|
||||
|
||||
if (WARN_ON(reg % 2))
|
||||
return -EINVAL;
|
||||
|
||||
if (dev->pdata && dev->pdata->big_endian)
|
||||
writew_be(value, regs + (page << 8) + reg);
|
||||
else
|
||||
writew(value, regs + (page << 8) + reg);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int b53_mmap_write32(struct b53_device *dev, u8 page, u8 reg,
|
||||
u32 value)
|
||||
{
|
||||
u8 __iomem *regs = dev->priv;
|
||||
|
||||
if (WARN_ON(reg % 4))
|
||||
return -EINVAL;
|
||||
|
||||
if (dev->pdata && dev->pdata->big_endian)
|
||||
writel_be(value, regs + (page << 8) + reg);
|
||||
else
|
||||
writel(value, regs + (page << 8) + reg);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int b53_mmap_write48(struct b53_device *dev, u8 page, u8 reg,
|
||||
u64 value)
|
||||
{
|
||||
if (WARN_ON(reg % 2))
|
||||
return -EINVAL;
|
||||
|
||||
if (reg % 4) {
|
||||
u32 hi = (u32)(value >> 16);
|
||||
u16 lo = (u16)value;
|
||||
|
||||
b53_mmap_write16(dev, page, reg, lo);
|
||||
b53_mmap_write32(dev, page, reg + 2, hi);
|
||||
} else {
|
||||
u16 hi = (u16)(value >> 32);
|
||||
u32 lo = (u32)value;
|
||||
|
||||
b53_mmap_write32(dev, page, reg, lo);
|
||||
b53_mmap_write16(dev, page, reg + 4, hi);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int b53_mmap_write64(struct b53_device *dev, u8 page, u8 reg,
|
||||
u64 value)
|
||||
{
|
||||
u32 hi, lo;
|
||||
|
||||
hi = (u32)(value >> 32);
|
||||
lo = (u32)value;
|
||||
|
||||
if (WARN_ON(reg % 4))
|
||||
return -EINVAL;
|
||||
|
||||
b53_mmap_write32(dev, page, reg, lo);
|
||||
b53_mmap_write32(dev, page, reg + 4, hi);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct b53_io_ops b53_mmap_ops = {
|
||||
.read8 = b53_mmap_read8,
|
||||
.read16 = b53_mmap_read16,
|
||||
.read32 = b53_mmap_read32,
|
||||
.read48 = b53_mmap_read48,
|
||||
.read64 = b53_mmap_read64,
|
||||
.write8 = b53_mmap_write8,
|
||||
.write16 = b53_mmap_write16,
|
||||
.write32 = b53_mmap_write32,
|
||||
.write48 = b53_mmap_write48,
|
||||
.write64 = b53_mmap_write64,
|
||||
};
|
||||
|
||||
static int b53_mmap_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct b53_platform_data *pdata = pdev->dev.platform_data;
|
||||
struct b53_device *dev;
|
||||
|
||||
if (!pdata)
|
||||
return -EINVAL;
|
||||
|
||||
dev = b53_swconfig_switch_alloc(&pdev->dev, &b53_mmap_ops, pdata->regs);
|
||||
if (!dev)
|
||||
return -ENOMEM;
|
||||
|
||||
if (pdata)
|
||||
dev->pdata = pdata;
|
||||
|
||||
platform_set_drvdata(pdev, dev);
|
||||
|
||||
return b53_swconfig_switch_register(dev);
|
||||
}
|
||||
|
||||
#if LINUX_VERSION_CODE < KERNEL_VERSION(6,11,0)
|
||||
static int b53_mmap_remove(struct platform_device *pdev)
|
||||
#else
|
||||
static void b53_mmap_remove(struct platform_device *pdev)
|
||||
#endif
|
||||
{
|
||||
struct b53_device *dev = platform_get_drvdata(pdev);
|
||||
|
||||
if (dev)
|
||||
b53_switch_remove(dev);
|
||||
|
||||
#if LINUX_VERSION_CODE < KERNEL_VERSION(6,11,0)
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
static struct platform_driver b53_mmap_driver = {
|
||||
.probe = b53_mmap_probe,
|
||||
.remove = b53_mmap_remove,
|
||||
.driver = {
|
||||
.name = "b53-switch",
|
||||
},
|
||||
};
|
||||
|
||||
module_platform_driver(b53_mmap_driver);
|
||||
MODULE_AUTHOR("Jonas Gorski <jogo@openwrt.org>");
|
||||
MODULE_DESCRIPTION("B53 MMAP access driver");
|
||||
MODULE_LICENSE("Dual BSD/GPL");
|
|
@ -0,0 +1,55 @@
|
|||
/*
|
||||
* B53 PHY Fixup call
|
||||
*
|
||||
* Copyright (C) 2013 Jonas Gorski <jogo@openwrt.org>
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <linux/init.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/phy.h>
|
||||
|
||||
#define B53_PSEUDO_PHY 0x1e /* Register Access Pseudo PHY */
|
||||
|
||||
#define B53_BRCM_OUI_1 0x0143bc00
|
||||
#define B53_BRCM_OUI_2 0x03625c00
|
||||
#define B53_BRCM_OUI_3 0x00406300
|
||||
|
||||
static int b53_phy_fixup(struct phy_device *dev)
|
||||
{
|
||||
struct mii_bus *bus = dev->mdio.bus;
|
||||
u32 phy_id;
|
||||
|
||||
if (dev->mdio.addr != B53_PSEUDO_PHY)
|
||||
return 0;
|
||||
|
||||
/* read the first port's id */
|
||||
phy_id = mdiobus_read(bus, 0, 2) << 16;
|
||||
phy_id |= mdiobus_read(bus, 0, 3);
|
||||
|
||||
if ((phy_id & 0xfffffc00) == B53_BRCM_OUI_1 ||
|
||||
(phy_id & 0xfffffc00) == B53_BRCM_OUI_2 ||
|
||||
(phy_id & 0xffffff00) == B53_BRCM_OUI_3) {
|
||||
dev->phy_id = phy_id;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int __init b53_phy_fixup_register(void)
|
||||
{
|
||||
return phy_register_fixup_for_id(PHY_ANY_ID, b53_phy_fixup);
|
||||
}
|
||||
|
||||
subsys_initcall(b53_phy_fixup_register);
|
336
6.12/target/linux/generic/files/drivers/net/phy/b53/b53_priv.h
Normal file
336
6.12/target/linux/generic/files/drivers/net/phy/b53/b53_priv.h
Normal file
|
@ -0,0 +1,336 @@
|
|||
/*
|
||||
* B53 common definitions
|
||||
*
|
||||
* Copyright (C) 2011-2013 Jonas Gorski <jogo@openwrt.org>
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef __B53_PRIV_H
|
||||
#define __B53_PRIV_H
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/switch.h>
|
||||
|
||||
struct b53_device;
|
||||
|
||||
struct b53_io_ops {
|
||||
int (*read8)(struct b53_device *dev, u8 page, u8 reg, u8 *value);
|
||||
int (*read16)(struct b53_device *dev, u8 page, u8 reg, u16 *value);
|
||||
int (*read32)(struct b53_device *dev, u8 page, u8 reg, u32 *value);
|
||||
int (*read48)(struct b53_device *dev, u8 page, u8 reg, u64 *value);
|
||||
int (*read64)(struct b53_device *dev, u8 page, u8 reg, u64 *value);
|
||||
int (*write8)(struct b53_device *dev, u8 page, u8 reg, u8 value);
|
||||
int (*write16)(struct b53_device *dev, u8 page, u8 reg, u16 value);
|
||||
int (*write32)(struct b53_device *dev, u8 page, u8 reg, u32 value);
|
||||
int (*write48)(struct b53_device *dev, u8 page, u8 reg, u64 value);
|
||||
int (*write64)(struct b53_device *dev, u8 page, u8 reg, u64 value);
|
||||
int (*phy_read16)(struct b53_device *dev, int addr, u8 reg, u16 *value);
|
||||
int (*phy_write16)(struct b53_device *dev, int addr, u8 reg, u16 value);
|
||||
};
|
||||
|
||||
enum {
|
||||
BCM5325_DEVICE_ID = 0x25,
|
||||
BCM5365_DEVICE_ID = 0x65,
|
||||
BCM5395_DEVICE_ID = 0x95,
|
||||
BCM5397_DEVICE_ID = 0x97,
|
||||
BCM5398_DEVICE_ID = 0x98,
|
||||
BCM53115_DEVICE_ID = 0x53115,
|
||||
BCM53125_DEVICE_ID = 0x53125,
|
||||
BCM53128_DEVICE_ID = 0x53128,
|
||||
BCM63XX_DEVICE_ID = 0x6300,
|
||||
BCM53010_DEVICE_ID = 0x53010,
|
||||
BCM53011_DEVICE_ID = 0x53011,
|
||||
BCM53012_DEVICE_ID = 0x53012,
|
||||
BCM53018_DEVICE_ID = 0x53018,
|
||||
BCM53019_DEVICE_ID = 0x53019,
|
||||
};
|
||||
|
||||
#define B53_N_PORTS 9
|
||||
#define B53_N_PORTS_25 6
|
||||
|
||||
struct b53_vlan {
|
||||
unsigned int members:B53_N_PORTS;
|
||||
unsigned int untag:B53_N_PORTS;
|
||||
};
|
||||
|
||||
struct b53_port {
|
||||
unsigned int pvid:12;
|
||||
};
|
||||
|
||||
struct b53_device {
|
||||
struct switch_dev sw_dev;
|
||||
struct b53_platform_data *pdata;
|
||||
|
||||
struct mutex reg_mutex;
|
||||
const struct b53_io_ops *ops;
|
||||
|
||||
/* chip specific data */
|
||||
u32 chip_id;
|
||||
u8 core_rev;
|
||||
u8 vta_regs[3];
|
||||
u8 duplex_reg;
|
||||
u8 jumbo_pm_reg;
|
||||
u8 jumbo_size_reg;
|
||||
int reset_gpio;
|
||||
|
||||
/* used ports mask */
|
||||
u16 enabled_ports;
|
||||
|
||||
/* connect specific data */
|
||||
u8 current_page;
|
||||
struct device *dev;
|
||||
void *priv;
|
||||
|
||||
/* run time configuration */
|
||||
unsigned enable_vlan:1;
|
||||
unsigned enable_jumbo:1;
|
||||
unsigned allow_vid_4095:1;
|
||||
|
||||
struct b53_port *ports;
|
||||
struct b53_vlan *vlans;
|
||||
|
||||
char *buf;
|
||||
};
|
||||
|
||||
#define b53_for_each_port(dev, i) \
|
||||
for (i = 0; i < B53_N_PORTS; i++) \
|
||||
if (dev->enabled_ports & BIT(i))
|
||||
|
||||
|
||||
|
||||
static inline int is5325(struct b53_device *dev)
|
||||
{
|
||||
return dev->chip_id == BCM5325_DEVICE_ID;
|
||||
}
|
||||
|
||||
static inline int is5365(struct b53_device *dev)
|
||||
{
|
||||
#ifdef CONFIG_BCM47XX
|
||||
return dev->chip_id == BCM5365_DEVICE_ID;
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline int is5397_98(struct b53_device *dev)
|
||||
{
|
||||
return dev->chip_id == BCM5397_DEVICE_ID ||
|
||||
dev->chip_id == BCM5398_DEVICE_ID;
|
||||
}
|
||||
|
||||
static inline int is539x(struct b53_device *dev)
|
||||
{
|
||||
return dev->chip_id == BCM5395_DEVICE_ID ||
|
||||
dev->chip_id == BCM5397_DEVICE_ID ||
|
||||
dev->chip_id == BCM5398_DEVICE_ID;
|
||||
}
|
||||
|
||||
static inline int is531x5(struct b53_device *dev)
|
||||
{
|
||||
return dev->chip_id == BCM53115_DEVICE_ID ||
|
||||
dev->chip_id == BCM53125_DEVICE_ID ||
|
||||
dev->chip_id == BCM53128_DEVICE_ID;
|
||||
}
|
||||
|
||||
static inline int is63xx(struct b53_device *dev)
|
||||
{
|
||||
#ifdef CONFIG_BCM63XX
|
||||
return dev->chip_id == BCM63XX_DEVICE_ID;
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline int is5301x(struct b53_device *dev)
|
||||
{
|
||||
return dev->chip_id == BCM53010_DEVICE_ID ||
|
||||
dev->chip_id == BCM53011_DEVICE_ID ||
|
||||
dev->chip_id == BCM53012_DEVICE_ID ||
|
||||
dev->chip_id == BCM53018_DEVICE_ID ||
|
||||
dev->chip_id == BCM53019_DEVICE_ID;
|
||||
}
|
||||
|
||||
#define B53_CPU_PORT_25 5
|
||||
#define B53_CPU_PORT 8
|
||||
|
||||
static inline int is_cpu_port(struct b53_device *dev, int port)
|
||||
{
|
||||
return dev->sw_dev.cpu_port == port;
|
||||
}
|
||||
|
||||
static inline int is_imp_port(struct b53_device *dev, int port)
|
||||
{
|
||||
if (is5325(dev) || is5365(dev))
|
||||
return port == B53_CPU_PORT_25;
|
||||
else
|
||||
return port == B53_CPU_PORT;
|
||||
}
|
||||
|
||||
static inline struct b53_device *sw_to_b53(struct switch_dev *sw)
|
||||
{
|
||||
return container_of(sw, struct b53_device, sw_dev);
|
||||
}
|
||||
|
||||
struct b53_device *b53_swconfig_switch_alloc(struct device *base, struct b53_io_ops *ops,
|
||||
void *priv);
|
||||
|
||||
int b53_swconfig_switch_detect(struct b53_device *dev);
|
||||
|
||||
int b53_swconfig_switch_register(struct b53_device *dev);
|
||||
|
||||
static inline void b53_switch_remove(struct b53_device *dev)
|
||||
{
|
||||
unregister_switch(&dev->sw_dev);
|
||||
}
|
||||
|
||||
static inline int b53_read8(struct b53_device *dev, u8 page, u8 reg, u8 *val)
|
||||
{
|
||||
int ret;
|
||||
|
||||
mutex_lock(&dev->reg_mutex);
|
||||
ret = dev->ops->read8(dev, page, reg, val);
|
||||
mutex_unlock(&dev->reg_mutex);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline int b53_read16(struct b53_device *dev, u8 page, u8 reg, u16 *val)
|
||||
{
|
||||
int ret;
|
||||
|
||||
mutex_lock(&dev->reg_mutex);
|
||||
ret = dev->ops->read16(dev, page, reg, val);
|
||||
mutex_unlock(&dev->reg_mutex);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline int b53_read32(struct b53_device *dev, u8 page, u8 reg, u32 *val)
|
||||
{
|
||||
int ret;
|
||||
|
||||
mutex_lock(&dev->reg_mutex);
|
||||
ret = dev->ops->read32(dev, page, reg, val);
|
||||
mutex_unlock(&dev->reg_mutex);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline int b53_read48(struct b53_device *dev, u8 page, u8 reg, u64 *val)
|
||||
{
|
||||
int ret;
|
||||
|
||||
mutex_lock(&dev->reg_mutex);
|
||||
ret = dev->ops->read48(dev, page, reg, val);
|
||||
mutex_unlock(&dev->reg_mutex);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline int b53_read64(struct b53_device *dev, u8 page, u8 reg, u64 *val)
|
||||
{
|
||||
int ret;
|
||||
|
||||
mutex_lock(&dev->reg_mutex);
|
||||
ret = dev->ops->read64(dev, page, reg, val);
|
||||
mutex_unlock(&dev->reg_mutex);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline int b53_write8(struct b53_device *dev, u8 page, u8 reg, u8 value)
|
||||
{
|
||||
int ret;
|
||||
|
||||
mutex_lock(&dev->reg_mutex);
|
||||
ret = dev->ops->write8(dev, page, reg, value);
|
||||
mutex_unlock(&dev->reg_mutex);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline int b53_write16(struct b53_device *dev, u8 page, u8 reg,
|
||||
u16 value)
|
||||
{
|
||||
int ret;
|
||||
|
||||
mutex_lock(&dev->reg_mutex);
|
||||
ret = dev->ops->write16(dev, page, reg, value);
|
||||
mutex_unlock(&dev->reg_mutex);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline int b53_write32(struct b53_device *dev, u8 page, u8 reg,
|
||||
u32 value)
|
||||
{
|
||||
int ret;
|
||||
|
||||
mutex_lock(&dev->reg_mutex);
|
||||
ret = dev->ops->write32(dev, page, reg, value);
|
||||
mutex_unlock(&dev->reg_mutex);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline int b53_write48(struct b53_device *dev, u8 page, u8 reg,
|
||||
u64 value)
|
||||
{
|
||||
int ret;
|
||||
|
||||
mutex_lock(&dev->reg_mutex);
|
||||
ret = dev->ops->write48(dev, page, reg, value);
|
||||
mutex_unlock(&dev->reg_mutex);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline int b53_write64(struct b53_device *dev, u8 page, u8 reg,
|
||||
u64 value)
|
||||
{
|
||||
int ret;
|
||||
|
||||
mutex_lock(&dev->reg_mutex);
|
||||
ret = dev->ops->write64(dev, page, reg, value);
|
||||
mutex_unlock(&dev->reg_mutex);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_BCM47XX
|
||||
#include <bcm47xx_board.h>
|
||||
#endif
|
||||
|
||||
#include <linux/version.h>
|
||||
#include <linux/bcm47xx_nvram.h>
|
||||
|
||||
static inline int b53_switch_get_reset_gpio(struct b53_device *dev)
|
||||
{
|
||||
#ifdef CONFIG_BCM47XX
|
||||
enum bcm47xx_board board = bcm47xx_board_get();
|
||||
|
||||
switch (board) {
|
||||
case BCM47XX_BOARD_LINKSYS_WRT300NV11:
|
||||
case BCM47XX_BOARD_LINKSYS_WRT310NV1:
|
||||
return 8;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
|
||||
return bcm47xx_nvram_gpio_pin("robo_reset");
|
||||
}
|
||||
|
||||
#endif
|
348
6.12/target/linux/generic/files/drivers/net/phy/b53/b53_regs.h
Normal file
348
6.12/target/linux/generic/files/drivers/net/phy/b53/b53_regs.h
Normal file
|
@ -0,0 +1,348 @@
|
|||
/*
|
||||
* B53 register definitions
|
||||
*
|
||||
* Copyright (C) 2004 Broadcom Corporation
|
||||
* Copyright (C) 2011-2013 Jonas Gorski <jogo@openwrt.org>
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef __B53_REGS_H
|
||||
#define __B53_REGS_H
|
||||
|
||||
/* Management Port (SMP) Page offsets */
|
||||
#define B53_CTRL_PAGE 0x00 /* Control */
|
||||
#define B53_STAT_PAGE 0x01 /* Status */
|
||||
#define B53_MGMT_PAGE 0x02 /* Management Mode */
|
||||
#define B53_MIB_AC_PAGE 0x03 /* MIB Autocast */
|
||||
#define B53_ARLCTRL_PAGE 0x04 /* ARL Control */
|
||||
#define B53_ARLIO_PAGE 0x05 /* ARL Access */
|
||||
#define B53_FRAMEBUF_PAGE 0x06 /* Management frame access */
|
||||
#define B53_MEM_ACCESS_PAGE 0x08 /* Memory access */
|
||||
|
||||
/* PHY Registers */
|
||||
#define B53_PORT_MII_PAGE(i) (0x10 + (i)) /* Port i MII Registers */
|
||||
#define B53_IM_PORT_PAGE 0x18 /* Inverse MII Port (to EMAC) */
|
||||
#define B53_ALL_PORT_PAGE 0x19 /* All ports MII (broadcast) */
|
||||
|
||||
/* MIB registers */
|
||||
#define B53_MIB_PAGE(i) (0x20 + (i))
|
||||
|
||||
/* Quality of Service (QoS) Registers */
|
||||
#define B53_QOS_PAGE 0x30
|
||||
|
||||
/* Port VLAN Page */
|
||||
#define B53_PVLAN_PAGE 0x31
|
||||
|
||||
/* VLAN Registers */
|
||||
#define B53_VLAN_PAGE 0x34
|
||||
|
||||
/* Jumbo Frame Registers */
|
||||
#define B53_JUMBO_PAGE 0x40
|
||||
|
||||
/* CFP Configuration Registers Page */
|
||||
#define B53_CFP_PAGE 0xa1
|
||||
|
||||
/*************************************************************************
|
||||
* Control Page registers
|
||||
*************************************************************************/
|
||||
|
||||
/* Port Control Register (8 bit) */
|
||||
#define B53_PORT_CTRL(i) (0x00 + (i))
|
||||
#define PORT_CTRL_RX_DISABLE BIT(0)
|
||||
#define PORT_CTRL_TX_DISABLE BIT(1)
|
||||
#define PORT_CTRL_RX_BCST_EN BIT(2) /* Broadcast RX (P8 only) */
|
||||
#define PORT_CTRL_RX_MCST_EN BIT(3) /* Multicast RX (P8 only) */
|
||||
#define PORT_CTRL_RX_UCST_EN BIT(4) /* Unicast RX (P8 only) */
|
||||
#define PORT_CTRL_STP_STATE_S 5
|
||||
#define PORT_CTRL_STP_STATE_MASK (0x7 << PORT_CTRL_STP_STATE_S)
|
||||
|
||||
/* SMP Control Register (8 bit) */
|
||||
#define B53_SMP_CTRL 0x0a
|
||||
|
||||
/* Switch Mode Control Register (8 bit) */
|
||||
#define B53_SWITCH_MODE 0x0b
|
||||
#define SM_SW_FWD_MODE BIT(0) /* 1 = Managed Mode */
|
||||
#define SM_SW_FWD_EN BIT(1) /* Forwarding Enable */
|
||||
|
||||
/* IMP Port state override register (8 bit) */
|
||||
#define B53_PORT_OVERRIDE_CTRL 0x0e
|
||||
#define PORT_OVERRIDE_LINK BIT(0)
|
||||
#define PORT_OVERRIDE_FULL_DUPLEX BIT(1) /* 0 = Half Duplex */
|
||||
#define PORT_OVERRIDE_SPEED_S 2
|
||||
#define PORT_OVERRIDE_SPEED_10M (0 << PORT_OVERRIDE_SPEED_S)
|
||||
#define PORT_OVERRIDE_SPEED_100M (1 << PORT_OVERRIDE_SPEED_S)
|
||||
#define PORT_OVERRIDE_SPEED_1000M (2 << PORT_OVERRIDE_SPEED_S)
|
||||
#define PORT_OVERRIDE_RV_MII_25 BIT(4) /* BCM5325 only */
|
||||
#define PORT_OVERRIDE_RX_FLOW BIT(4)
|
||||
#define PORT_OVERRIDE_TX_FLOW BIT(5)
|
||||
#define PORT_OVERRIDE_SPEED_2000M BIT(6) /* BCM5301X only, requires setting 1000M */
|
||||
#define PORT_OVERRIDE_EN BIT(7) /* Use the register contents */
|
||||
|
||||
/* Power-down mode control */
|
||||
#define B53_PD_MODE_CTRL_25 0x0f
|
||||
|
||||
/* IP Multicast control (8 bit) */
|
||||
#define B53_IP_MULTICAST_CTRL 0x21
|
||||
#define B53_IPMC_FWD_EN BIT(1)
|
||||
#define B53_UC_FWD_EN BIT(6)
|
||||
#define B53_MC_FWD_EN BIT(7)
|
||||
|
||||
/* (16 bit) */
|
||||
#define B53_UC_FLOOD_MASK 0x32
|
||||
#define B53_MC_FLOOD_MASK 0x34
|
||||
#define B53_IPMC_FLOOD_MASK 0x36
|
||||
|
||||
/*
|
||||
* Override Ports 0-7 State on devices with xMII interfaces (8 bit)
|
||||
*
|
||||
* For port 8 still use B53_PORT_OVERRIDE_CTRL
|
||||
* Please note that not all ports are available on every hardware, e.g. BCM5301X
|
||||
* don't include overriding port 6, BCM63xx also have some limitations.
|
||||
*/
|
||||
#define B53_GMII_PORT_OVERRIDE_CTRL(i) (0x58 + (i))
|
||||
#define GMII_PO_LINK BIT(0)
|
||||
#define GMII_PO_FULL_DUPLEX BIT(1) /* 0 = Half Duplex */
|
||||
#define GMII_PO_SPEED_S 2
|
||||
#define GMII_PO_SPEED_10M (0 << GMII_PO_SPEED_S)
|
||||
#define GMII_PO_SPEED_100M (1 << GMII_PO_SPEED_S)
|
||||
#define GMII_PO_SPEED_1000M (2 << GMII_PO_SPEED_S)
|
||||
#define GMII_PO_RX_FLOW BIT(4)
|
||||
#define GMII_PO_TX_FLOW BIT(5)
|
||||
#define GMII_PO_EN BIT(6) /* Use the register contents */
|
||||
#define GMII_PO_SPEED_2000M BIT(7) /* BCM5301X only, requires setting 1000M */
|
||||
|
||||
/* Software reset register (8 bit) */
|
||||
#define B53_SOFTRESET 0x79
|
||||
|
||||
/* Fast Aging Control register (8 bit) */
|
||||
#define B53_FAST_AGE_CTRL 0x88
|
||||
#define FAST_AGE_STATIC BIT(0)
|
||||
#define FAST_AGE_DYNAMIC BIT(1)
|
||||
#define FAST_AGE_PORT BIT(2)
|
||||
#define FAST_AGE_VLAN BIT(3)
|
||||
#define FAST_AGE_STP BIT(4)
|
||||
#define FAST_AGE_MC BIT(5)
|
||||
#define FAST_AGE_DONE BIT(7)
|
||||
|
||||
/*************************************************************************
|
||||
* Status Page registers
|
||||
*************************************************************************/
|
||||
|
||||
/* Link Status Summary Register (16bit) */
|
||||
#define B53_LINK_STAT 0x00
|
||||
|
||||
/* Link Status Change Register (16 bit) */
|
||||
#define B53_LINK_STAT_CHANGE 0x02
|
||||
|
||||
/* Port Speed Summary Register (16 bit for FE, 32 bit for GE) */
|
||||
#define B53_SPEED_STAT 0x04
|
||||
#define SPEED_PORT_FE(reg, port) (((reg) >> (port)) & 1)
|
||||
#define SPEED_PORT_GE(reg, port) (((reg) >> 2 * (port)) & 3)
|
||||
#define SPEED_STAT_10M 0
|
||||
#define SPEED_STAT_100M 1
|
||||
#define SPEED_STAT_1000M 2
|
||||
|
||||
/* Duplex Status Summary (16 bit) */
|
||||
#define B53_DUPLEX_STAT_FE 0x06
|
||||
#define B53_DUPLEX_STAT_GE 0x08
|
||||
#define B53_DUPLEX_STAT_63XX 0x0c
|
||||
|
||||
/* Revision ID register for BCM5325 */
|
||||
#define B53_REV_ID_25 0x50
|
||||
|
||||
/* Strap Value (48 bit) */
|
||||
#define B53_STRAP_VALUE 0x70
|
||||
#define SV_GMII_CTRL_115 BIT(27)
|
||||
|
||||
/*************************************************************************
|
||||
* Management Mode Page Registers
|
||||
*************************************************************************/
|
||||
|
||||
/* Global Management Config Register (8 bit) */
|
||||
#define B53_GLOBAL_CONFIG 0x00
|
||||
#define GC_RESET_MIB 0x01
|
||||
#define GC_RX_BPDU_EN 0x02
|
||||
#define GC_MIB_AC_HDR_EN 0x10
|
||||
#define GC_MIB_AC_EN 0x20
|
||||
#define GC_FRM_MGMT_PORT_M 0xC0
|
||||
#define GC_FRM_MGMT_PORT_04 0x00
|
||||
#define GC_FRM_MGMT_PORT_MII 0x80
|
||||
|
||||
/* Broadcom Header control register (8 bit) */
|
||||
#define B53_BRCM_HDR 0x03
|
||||
#define BRCM_HDR_P8_EN BIT(0) /* Enable tagging on port 8 */
|
||||
#define BRCM_HDR_P5_EN BIT(1) /* Enable tagging on port 5 */
|
||||
|
||||
/* Device ID register (8 or 32 bit) */
|
||||
#define B53_DEVICE_ID 0x30
|
||||
|
||||
/* Revision ID register (8 bit) */
|
||||
#define B53_REV_ID 0x40
|
||||
|
||||
/*************************************************************************
|
||||
* ARL Access Page Registers
|
||||
*************************************************************************/
|
||||
|
||||
/* VLAN Table Access Register (8 bit) */
|
||||
#define B53_VT_ACCESS 0x80
|
||||
#define B53_VT_ACCESS_9798 0x60 /* for BCM5397/BCM5398 */
|
||||
#define B53_VT_ACCESS_63XX 0x60 /* for BCM6328/62/68 */
|
||||
#define VTA_CMD_WRITE 0
|
||||
#define VTA_CMD_READ 1
|
||||
#define VTA_CMD_CLEAR 2
|
||||
#define VTA_START_CMD BIT(7)
|
||||
|
||||
/* VLAN Table Index Register (16 bit) */
|
||||
#define B53_VT_INDEX 0x81
|
||||
#define B53_VT_INDEX_9798 0x61
|
||||
#define B53_VT_INDEX_63XX 0x62
|
||||
|
||||
/* VLAN Table Entry Register (32 bit) */
|
||||
#define B53_VT_ENTRY 0x83
|
||||
#define B53_VT_ENTRY_9798 0x63
|
||||
#define B53_VT_ENTRY_63XX 0x64
|
||||
#define VTE_MEMBERS 0x1ff
|
||||
#define VTE_UNTAG_S 9
|
||||
#define VTE_UNTAG (0x1ff << 9)
|
||||
|
||||
/*************************************************************************
|
||||
* Port VLAN Registers
|
||||
*************************************************************************/
|
||||
|
||||
/* Port VLAN mask (16 bit) IMP port is always 8, also on 5325 & co */
|
||||
#define B53_PVLAN_PORT_MASK(i) ((i) * 2)
|
||||
|
||||
/*************************************************************************
|
||||
* 802.1Q Page Registers
|
||||
*************************************************************************/
|
||||
|
||||
/* Global QoS Control (8 bit) */
|
||||
#define B53_QOS_GLOBAL_CTL 0x00
|
||||
|
||||
/* Enable 802.1Q for individual Ports (16 bit) */
|
||||
#define B53_802_1P_EN 0x04
|
||||
|
||||
/*************************************************************************
|
||||
* VLAN Page Registers
|
||||
*************************************************************************/
|
||||
|
||||
/* VLAN Control 0 (8 bit) */
|
||||
#define B53_VLAN_CTRL0 0x00
|
||||
#define VC0_8021PF_CTRL_MASK 0x3
|
||||
#define VC0_8021PF_CTRL_NONE 0x0
|
||||
#define VC0_8021PF_CTRL_CHANGE_PRI 0x1
|
||||
#define VC0_8021PF_CTRL_CHANGE_VID 0x2
|
||||
#define VC0_8021PF_CTRL_CHANGE_BOTH 0x3
|
||||
#define VC0_8021QF_CTRL_MASK 0xc
|
||||
#define VC0_8021QF_CTRL_CHANGE_PRI 0x1
|
||||
#define VC0_8021QF_CTRL_CHANGE_VID 0x2
|
||||
#define VC0_8021QF_CTRL_CHANGE_BOTH 0x3
|
||||
#define VC0_RESERVED_1 BIT(1)
|
||||
#define VC0_DROP_VID_MISS BIT(4)
|
||||
#define VC0_VID_HASH_VID BIT(5)
|
||||
#define VC0_VID_CHK_EN BIT(6) /* Use VID,DA or VID,SA */
|
||||
#define VC0_VLAN_EN BIT(7) /* 802.1Q VLAN Enabled */
|
||||
|
||||
/* VLAN Control 1 (8 bit) */
|
||||
#define B53_VLAN_CTRL1 0x01
|
||||
#define VC1_RX_MCST_TAG_EN BIT(1)
|
||||
#define VC1_RX_MCST_FWD_EN BIT(2)
|
||||
#define VC1_RX_MCST_UNTAG_EN BIT(3)
|
||||
|
||||
/* VLAN Control 2 (8 bit) */
|
||||
#define B53_VLAN_CTRL2 0x02
|
||||
|
||||
/* VLAN Control 3 (8 bit when BCM5325, 16 bit else) */
|
||||
#define B53_VLAN_CTRL3 0x03
|
||||
#define B53_VLAN_CTRL3_63XX 0x04
|
||||
#define VC3_MAXSIZE_1532 BIT(6) /* 5325 only */
|
||||
#define VC3_HIGH_8BIT_EN BIT(7) /* 5325 only */
|
||||
|
||||
/* VLAN Control 4 (8 bit) */
|
||||
#define B53_VLAN_CTRL4 0x05
|
||||
#define B53_VLAN_CTRL4_25 0x04
|
||||
#define B53_VLAN_CTRL4_63XX 0x06
|
||||
#define VC4_ING_VID_CHECK_S 6
|
||||
#define VC4_ING_VID_CHECK_MASK (0x3 << VC4_ING_VID_CHECK_S)
|
||||
#define VC4_ING_VID_VIO_FWD 0 /* forward, but do not learn */
|
||||
#define VC4_ING_VID_VIO_DROP 1 /* drop VID violations */
|
||||
#define VC4_NO_ING_VID_CHK 2 /* do not check */
|
||||
#define VC4_ING_VID_VIO_TO_IMP 3 /* redirect to MII port */
|
||||
|
||||
/* VLAN Control 5 (8 bit) */
|
||||
#define B53_VLAN_CTRL5 0x06
|
||||
#define B53_VLAN_CTRL5_25 0x05
|
||||
#define B53_VLAN_CTRL5_63XX 0x07
|
||||
#define VC5_VID_FFF_EN BIT(2)
|
||||
#define VC5_DROP_VTABLE_MISS BIT(3)
|
||||
|
||||
/* VLAN Control 6 (8 bit) */
|
||||
#define B53_VLAN_CTRL6 0x07
|
||||
#define B53_VLAN_CTRL6_63XX 0x08
|
||||
|
||||
/* VLAN Table Access Register (16 bit) */
|
||||
#define B53_VLAN_TABLE_ACCESS_25 0x06 /* BCM5325E/5350 */
|
||||
#define B53_VLAN_TABLE_ACCESS_65 0x08 /* BCM5365 */
|
||||
#define VTA_VID_LOW_MASK_25 0xf
|
||||
#define VTA_VID_LOW_MASK_65 0xff
|
||||
#define VTA_VID_HIGH_S_25 4
|
||||
#define VTA_VID_HIGH_S_65 8
|
||||
#define VTA_VID_HIGH_MASK_25 (0xff << VTA_VID_HIGH_S_25E)
|
||||
#define VTA_VID_HIGH_MASK_65 (0xf << VTA_VID_HIGH_S_65)
|
||||
#define VTA_RW_STATE BIT(12)
|
||||
#define VTA_RW_STATE_RD 0
|
||||
#define VTA_RW_STATE_WR BIT(12)
|
||||
#define VTA_RW_OP_EN BIT(13)
|
||||
|
||||
/* VLAN Read/Write Registers for (16/32 bit) */
|
||||
#define B53_VLAN_WRITE_25 0x08
|
||||
#define B53_VLAN_WRITE_65 0x0a
|
||||
#define B53_VLAN_READ 0x0c
|
||||
#define VA_MEMBER_MASK 0x3f
|
||||
#define VA_UNTAG_S_25 6
|
||||
#define VA_UNTAG_MASK_25 0x3f
|
||||
#define VA_UNTAG_S_65 7
|
||||
#define VA_UNTAG_MASK_65 0x1f
|
||||
#define VA_VID_HIGH_S 12
|
||||
#define VA_VID_HIGH_MASK (0xffff << VA_VID_HIGH_S)
|
||||
#define VA_VALID_25 BIT(20)
|
||||
#define VA_VALID_25_R4 BIT(24)
|
||||
#define VA_VALID_65 BIT(14)
|
||||
|
||||
/* VLAN Port Default Tag (16 bit) */
|
||||
#define B53_VLAN_PORT_DEF_TAG(i) (0x10 + 2 * (i))
|
||||
|
||||
/*************************************************************************
|
||||
* Jumbo Frame Page Registers
|
||||
*************************************************************************/
|
||||
|
||||
/* Jumbo Enable Port Mask (bit i == port i enabled) (32 bit) */
|
||||
#define B53_JUMBO_PORT_MASK 0x01
|
||||
#define B53_JUMBO_PORT_MASK_63XX 0x04
|
||||
#define JPM_10_100_JUMBO_EN BIT(24) /* GigE always enabled */
|
||||
|
||||
/* Good Frame Max Size without 802.1Q TAG (16 bit) */
|
||||
#define B53_JUMBO_MAX_SIZE 0x05
|
||||
#define B53_JUMBO_MAX_SIZE_63XX 0x08
|
||||
#define JMS_MIN_SIZE 1518
|
||||
#define JMS_MAX_SIZE 9724
|
||||
|
||||
/*************************************************************************
|
||||
* CFP Configuration Page Registers
|
||||
*************************************************************************/
|
||||
|
||||
/* CFP Control Register with ports map (8 bit) */
|
||||
#define B53_CFP_CTRL 0x00
|
||||
|
||||
#endif /* !__B53_REGS_H */
|
344
6.12/target/linux/generic/files/drivers/net/phy/b53/b53_spi.c
Normal file
344
6.12/target/linux/generic/files/drivers/net/phy/b53/b53_spi.c
Normal file
|
@ -0,0 +1,344 @@
|
|||
/*
|
||||
* B53 register access through SPI
|
||||
*
|
||||
* Copyright (C) 2011-2013 Jonas Gorski <jogo@openwrt.org>
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <asm/unaligned.h>
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/spi/spi.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/platform_data/b53.h>
|
||||
|
||||
#include "b53_priv.h"
|
||||
|
||||
#define B53_SPI_DATA 0xf0
|
||||
|
||||
#define B53_SPI_STATUS 0xfe
|
||||
#define B53_SPI_CMD_SPIF BIT(7)
|
||||
#define B53_SPI_CMD_RACK BIT(5)
|
||||
|
||||
#define B53_SPI_CMD_READ 0x00
|
||||
#define B53_SPI_CMD_WRITE 0x01
|
||||
#define B53_SPI_CMD_NORMAL 0x60
|
||||
#define B53_SPI_CMD_FAST 0x10
|
||||
|
||||
#define B53_SPI_PAGE_SELECT 0xff
|
||||
|
||||
static inline int b53_spi_read_reg(struct spi_device *spi, u8 reg, u8 *val,
|
||||
unsigned len)
|
||||
{
|
||||
u8 txbuf[2];
|
||||
|
||||
txbuf[0] = B53_SPI_CMD_NORMAL | B53_SPI_CMD_READ;
|
||||
txbuf[1] = reg;
|
||||
|
||||
return spi_write_then_read(spi, txbuf, 2, val, len);
|
||||
}
|
||||
|
||||
static inline int b53_spi_clear_status(struct spi_device *spi)
|
||||
{
|
||||
unsigned int i;
|
||||
u8 rxbuf;
|
||||
int ret;
|
||||
|
||||
for (i = 0; i < 10; i++) {
|
||||
ret = b53_spi_read_reg(spi, B53_SPI_STATUS, &rxbuf, 1);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (!(rxbuf & B53_SPI_CMD_SPIF))
|
||||
break;
|
||||
|
||||
mdelay(1);
|
||||
}
|
||||
|
||||
if (i == 10)
|
||||
return -EIO;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int b53_spi_set_page(struct spi_device *spi, u8 page)
|
||||
{
|
||||
u8 txbuf[3];
|
||||
|
||||
txbuf[0] = B53_SPI_CMD_NORMAL | B53_SPI_CMD_WRITE;
|
||||
txbuf[1] = B53_SPI_PAGE_SELECT;
|
||||
txbuf[2] = page;
|
||||
|
||||
return spi_write(spi, txbuf, sizeof(txbuf));
|
||||
}
|
||||
|
||||
static inline int b53_prepare_reg_access(struct spi_device *spi, u8 page)
|
||||
{
|
||||
int ret = b53_spi_clear_status(spi);
|
||||
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return b53_spi_set_page(spi, page);
|
||||
}
|
||||
|
||||
static int b53_spi_prepare_reg_read(struct spi_device *spi, u8 reg)
|
||||
{
|
||||
u8 rxbuf;
|
||||
int retry_count;
|
||||
int ret;
|
||||
|
||||
ret = b53_spi_read_reg(spi, reg, &rxbuf, 1);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
for (retry_count = 0; retry_count < 10; retry_count++) {
|
||||
ret = b53_spi_read_reg(spi, B53_SPI_STATUS, &rxbuf, 1);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (rxbuf & B53_SPI_CMD_RACK)
|
||||
break;
|
||||
|
||||
mdelay(1);
|
||||
}
|
||||
|
||||
if (retry_count == 10)
|
||||
return -EIO;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int b53_spi_read(struct b53_device *dev, u8 page, u8 reg, u8 *data,
|
||||
unsigned len)
|
||||
{
|
||||
struct spi_device *spi = dev->priv;
|
||||
int ret;
|
||||
|
||||
ret = b53_prepare_reg_access(spi, page);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = b53_spi_prepare_reg_read(spi, reg);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return b53_spi_read_reg(spi, B53_SPI_DATA, data, len);
|
||||
}
|
||||
|
||||
static int b53_spi_read8(struct b53_device *dev, u8 page, u8 reg, u8 *val)
|
||||
{
|
||||
return b53_spi_read(dev, page, reg, val, 1);
|
||||
}
|
||||
|
||||
static int b53_spi_read16(struct b53_device *dev, u8 page, u8 reg, u16 *val)
|
||||
{
|
||||
int ret = b53_spi_read(dev, page, reg, (u8 *)val, 2);
|
||||
|
||||
if (!ret)
|
||||
*val = le16_to_cpu(*val);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int b53_spi_read32(struct b53_device *dev, u8 page, u8 reg, u32 *val)
|
||||
{
|
||||
int ret = b53_spi_read(dev, page, reg, (u8 *)val, 4);
|
||||
|
||||
if (!ret)
|
||||
*val = le32_to_cpu(*val);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int b53_spi_read48(struct b53_device *dev, u8 page, u8 reg, u64 *val)
|
||||
{
|
||||
int ret;
|
||||
|
||||
*val = 0;
|
||||
ret = b53_spi_read(dev, page, reg, (u8 *)val, 6);
|
||||
if (!ret)
|
||||
*val = le64_to_cpu(*val);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int b53_spi_read64(struct b53_device *dev, u8 page, u8 reg, u64 *val)
|
||||
{
|
||||
int ret = b53_spi_read(dev, page, reg, (u8 *)val, 8);
|
||||
|
||||
if (!ret)
|
||||
*val = le64_to_cpu(*val);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int b53_spi_write8(struct b53_device *dev, u8 page, u8 reg, u8 value)
|
||||
{
|
||||
struct spi_device *spi = dev->priv;
|
||||
int ret;
|
||||
u8 txbuf[3];
|
||||
|
||||
ret = b53_prepare_reg_access(spi, page);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
txbuf[0] = B53_SPI_CMD_NORMAL | B53_SPI_CMD_WRITE;
|
||||
txbuf[1] = reg;
|
||||
txbuf[2] = value;
|
||||
|
||||
return spi_write(spi, txbuf, sizeof(txbuf));
|
||||
}
|
||||
|
||||
static int b53_spi_write16(struct b53_device *dev, u8 page, u8 reg, u16 value)
|
||||
{
|
||||
struct spi_device *spi = dev->priv;
|
||||
int ret;
|
||||
u8 txbuf[4];
|
||||
|
||||
ret = b53_prepare_reg_access(spi, page);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
txbuf[0] = B53_SPI_CMD_NORMAL | B53_SPI_CMD_WRITE;
|
||||
txbuf[1] = reg;
|
||||
put_unaligned_le16(value, &txbuf[2]);
|
||||
|
||||
return spi_write(spi, txbuf, sizeof(txbuf));
|
||||
}
|
||||
|
||||
static int b53_spi_write32(struct b53_device *dev, u8 page, u8 reg, u32 value)
|
||||
{
|
||||
struct spi_device *spi = dev->priv;
|
||||
int ret;
|
||||
u8 txbuf[6];
|
||||
|
||||
ret = b53_prepare_reg_access(spi, page);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
txbuf[0] = B53_SPI_CMD_NORMAL | B53_SPI_CMD_WRITE;
|
||||
txbuf[1] = reg;
|
||||
put_unaligned_le32(value, &txbuf[2]);
|
||||
|
||||
return spi_write(spi, txbuf, sizeof(txbuf));
|
||||
}
|
||||
|
||||
static int b53_spi_write48(struct b53_device *dev, u8 page, u8 reg, u64 value)
|
||||
{
|
||||
struct spi_device *spi = dev->priv;
|
||||
int ret;
|
||||
u8 txbuf[10];
|
||||
|
||||
ret = b53_prepare_reg_access(spi, page);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
txbuf[0] = B53_SPI_CMD_NORMAL | B53_SPI_CMD_WRITE;
|
||||
txbuf[1] = reg;
|
||||
put_unaligned_le64(value, &txbuf[2]);
|
||||
|
||||
return spi_write(spi, txbuf, sizeof(txbuf) - 2);
|
||||
}
|
||||
|
||||
static int b53_spi_write64(struct b53_device *dev, u8 page, u8 reg, u64 value)
|
||||
{
|
||||
struct spi_device *spi = dev->priv;
|
||||
int ret;
|
||||
u8 txbuf[10];
|
||||
|
||||
ret = b53_prepare_reg_access(spi, page);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
txbuf[0] = B53_SPI_CMD_NORMAL | B53_SPI_CMD_WRITE;
|
||||
txbuf[1] = reg;
|
||||
put_unaligned_le64(value, &txbuf[2]);
|
||||
|
||||
return spi_write(spi, txbuf, sizeof(txbuf));
|
||||
}
|
||||
|
||||
static struct b53_io_ops b53_spi_ops = {
|
||||
.read8 = b53_spi_read8,
|
||||
.read16 = b53_spi_read16,
|
||||
.read32 = b53_spi_read32,
|
||||
.read48 = b53_spi_read48,
|
||||
.read64 = b53_spi_read64,
|
||||
.write8 = b53_spi_write8,
|
||||
.write16 = b53_spi_write16,
|
||||
.write32 = b53_spi_write32,
|
||||
.write48 = b53_spi_write48,
|
||||
.write64 = b53_spi_write64,
|
||||
};
|
||||
|
||||
static int b53_spi_probe(struct spi_device *spi)
|
||||
{
|
||||
struct b53_device *dev;
|
||||
int ret;
|
||||
|
||||
dev = b53_swconfig_switch_alloc(&spi->dev, &b53_spi_ops, spi);
|
||||
if (!dev)
|
||||
return -ENOMEM;
|
||||
|
||||
if (spi->dev.platform_data)
|
||||
dev->pdata = spi->dev.platform_data;
|
||||
|
||||
ret = b53_swconfig_switch_register(dev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
spi_set_drvdata(spi, dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int b53_spi_remove(struct spi_device *spi)
|
||||
{
|
||||
struct b53_device *dev = spi_get_drvdata(spi);
|
||||
|
||||
if (dev)
|
||||
b53_switch_remove(dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct of_device_id b53_of_match[] = {
|
||||
{ .compatible = "brcm,bcm5325" },
|
||||
{ .compatible = "brcm,bcm53115" },
|
||||
{ .compatible = "brcm,bcm53125" },
|
||||
{ .compatible = "brcm,bcm53128" },
|
||||
{ .compatible = "brcm,bcm5365" },
|
||||
{ .compatible = "brcm,bcm5395" },
|
||||
{ .compatible = "brcm,bcm5397" },
|
||||
{ .compatible = "brcm,bcm5398" },
|
||||
{ /* sentinel */ },
|
||||
};
|
||||
|
||||
static struct spi_driver b53_spi_driver = {
|
||||
.driver = {
|
||||
.name = "b53-switch",
|
||||
.bus = &spi_bus_type,
|
||||
.owner = THIS_MODULE,
|
||||
.of_match_table = b53_of_match,
|
||||
},
|
||||
.probe = b53_spi_probe,
|
||||
.remove = b53_spi_remove,
|
||||
};
|
||||
|
||||
module_spi_driver(b53_spi_driver);
|
||||
|
||||
MODULE_AUTHOR("Jonas Gorski <jogo@openwrt.org>");
|
||||
MODULE_DESCRIPTION("B53 SPI access driver");
|
||||
MODULE_LICENSE("Dual BSD/GPL");
|
385
6.12/target/linux/generic/files/drivers/net/phy/b53/b53_srab.c
Normal file
385
6.12/target/linux/generic/files/drivers/net/phy/b53/b53_srab.c
Normal file
|
@ -0,0 +1,385 @@
|
|||
/*
|
||||
* B53 register access through Switch Register Access Bridge Registers
|
||||
*
|
||||
* Copyright (C) 2013 Hauke Mehrtens <hauke@hauke-m.de>
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/platform_data/b53.h>
|
||||
#include <linux/version.h>
|
||||
|
||||
#include "b53_priv.h"
|
||||
|
||||
/* command and status register of the SRAB */
|
||||
#define B53_SRAB_CMDSTAT 0x2c
|
||||
#define B53_SRAB_CMDSTAT_RST BIT(2)
|
||||
#define B53_SRAB_CMDSTAT_WRITE BIT(1)
|
||||
#define B53_SRAB_CMDSTAT_GORDYN BIT(0)
|
||||
#define B53_SRAB_CMDSTAT_PAGE 24
|
||||
#define B53_SRAB_CMDSTAT_REG 16
|
||||
|
||||
/* high order word of write data to switch registe */
|
||||
#define B53_SRAB_WD_H 0x30
|
||||
|
||||
/* low order word of write data to switch registe */
|
||||
#define B53_SRAB_WD_L 0x34
|
||||
|
||||
/* high order word of read data from switch register */
|
||||
#define B53_SRAB_RD_H 0x38
|
||||
|
||||
/* low order word of read data from switch register */
|
||||
#define B53_SRAB_RD_L 0x3c
|
||||
|
||||
/* command and status register of the SRAB */
|
||||
#define B53_SRAB_CTRLS 0x40
|
||||
#define B53_SRAB_CTRLS_RCAREQ BIT(3)
|
||||
#define B53_SRAB_CTRLS_RCAGNT BIT(4)
|
||||
#define B53_SRAB_CTRLS_SW_INIT_DONE BIT(6)
|
||||
|
||||
/* the register captures interrupt pulses from the switch */
|
||||
#define B53_SRAB_INTR 0x44
|
||||
|
||||
static int b53_srab_request_grant(struct b53_device *dev)
|
||||
{
|
||||
u8 __iomem *regs = dev->priv;
|
||||
u32 ctrls;
|
||||
int i;
|
||||
|
||||
ctrls = readl(regs + B53_SRAB_CTRLS);
|
||||
ctrls |= B53_SRAB_CTRLS_RCAREQ;
|
||||
writel(ctrls, regs + B53_SRAB_CTRLS);
|
||||
|
||||
for (i = 0; i < 20; i++) {
|
||||
ctrls = readl(regs + B53_SRAB_CTRLS);
|
||||
if (ctrls & B53_SRAB_CTRLS_RCAGNT)
|
||||
break;
|
||||
usleep_range(10, 100);
|
||||
}
|
||||
if (WARN_ON(i == 5))
|
||||
return -EIO;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void b53_srab_release_grant(struct b53_device *dev)
|
||||
{
|
||||
u8 __iomem *regs = dev->priv;
|
||||
u32 ctrls;
|
||||
|
||||
ctrls = readl(regs + B53_SRAB_CTRLS);
|
||||
ctrls &= ~B53_SRAB_CTRLS_RCAREQ;
|
||||
writel(ctrls, regs + B53_SRAB_CTRLS);
|
||||
}
|
||||
|
||||
static int b53_srab_op(struct b53_device *dev, u8 page, u8 reg, u32 op)
|
||||
{
|
||||
int i;
|
||||
u32 cmdstat;
|
||||
u8 __iomem *regs = dev->priv;
|
||||
|
||||
/* set register address */
|
||||
cmdstat = (page << B53_SRAB_CMDSTAT_PAGE) |
|
||||
(reg << B53_SRAB_CMDSTAT_REG) |
|
||||
B53_SRAB_CMDSTAT_GORDYN |
|
||||
op;
|
||||
writel(cmdstat, regs + B53_SRAB_CMDSTAT);
|
||||
|
||||
/* check if operation completed */
|
||||
for (i = 0; i < 5; ++i) {
|
||||
cmdstat = readl(regs + B53_SRAB_CMDSTAT);
|
||||
if (!(cmdstat & B53_SRAB_CMDSTAT_GORDYN))
|
||||
break;
|
||||
usleep_range(10, 100);
|
||||
}
|
||||
|
||||
if (WARN_ON(i == 5))
|
||||
return -EIO;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int b53_srab_read8(struct b53_device *dev, u8 page, u8 reg, u8 *val)
|
||||
{
|
||||
u8 __iomem *regs = dev->priv;
|
||||
int ret = 0;
|
||||
|
||||
ret = b53_srab_request_grant(dev);
|
||||
if (ret)
|
||||
goto err;
|
||||
|
||||
ret = b53_srab_op(dev, page, reg, 0);
|
||||
if (ret)
|
||||
goto err;
|
||||
|
||||
*val = readl(regs + B53_SRAB_RD_L) & 0xff;
|
||||
|
||||
err:
|
||||
b53_srab_release_grant(dev);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int b53_srab_read16(struct b53_device *dev, u8 page, u8 reg, u16 *val)
|
||||
{
|
||||
u8 __iomem *regs = dev->priv;
|
||||
int ret = 0;
|
||||
|
||||
ret = b53_srab_request_grant(dev);
|
||||
if (ret)
|
||||
goto err;
|
||||
|
||||
ret = b53_srab_op(dev, page, reg, 0);
|
||||
if (ret)
|
||||
goto err;
|
||||
|
||||
*val = readl(regs + B53_SRAB_RD_L) & 0xffff;
|
||||
|
||||
err:
|
||||
b53_srab_release_grant(dev);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int b53_srab_read32(struct b53_device *dev, u8 page, u8 reg, u32 *val)
|
||||
{
|
||||
u8 __iomem *regs = dev->priv;
|
||||
int ret = 0;
|
||||
|
||||
ret = b53_srab_request_grant(dev);
|
||||
if (ret)
|
||||
goto err;
|
||||
|
||||
ret = b53_srab_op(dev, page, reg, 0);
|
||||
if (ret)
|
||||
goto err;
|
||||
|
||||
*val = readl(regs + B53_SRAB_RD_L);
|
||||
|
||||
err:
|
||||
b53_srab_release_grant(dev);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int b53_srab_read48(struct b53_device *dev, u8 page, u8 reg, u64 *val)
|
||||
{
|
||||
u8 __iomem *regs = dev->priv;
|
||||
int ret = 0;
|
||||
|
||||
ret = b53_srab_request_grant(dev);
|
||||
if (ret)
|
||||
goto err;
|
||||
|
||||
ret = b53_srab_op(dev, page, reg, 0);
|
||||
if (ret)
|
||||
goto err;
|
||||
|
||||
*val = readl(regs + B53_SRAB_RD_L);
|
||||
*val += ((u64)readl(regs + B53_SRAB_RD_H) & 0xffff) << 32;
|
||||
|
||||
err:
|
||||
b53_srab_release_grant(dev);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int b53_srab_read64(struct b53_device *dev, u8 page, u8 reg, u64 *val)
|
||||
{
|
||||
u8 __iomem *regs = dev->priv;
|
||||
int ret = 0;
|
||||
|
||||
ret = b53_srab_request_grant(dev);
|
||||
if (ret)
|
||||
goto err;
|
||||
|
||||
ret = b53_srab_op(dev, page, reg, 0);
|
||||
if (ret)
|
||||
goto err;
|
||||
|
||||
*val = readl(regs + B53_SRAB_RD_L);
|
||||
*val += (u64)readl(regs + B53_SRAB_RD_H) << 32;
|
||||
|
||||
err:
|
||||
b53_srab_release_grant(dev);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int b53_srab_write8(struct b53_device *dev, u8 page, u8 reg, u8 value)
|
||||
{
|
||||
u8 __iomem *regs = dev->priv;
|
||||
int ret = 0;
|
||||
|
||||
ret = b53_srab_request_grant(dev);
|
||||
if (ret)
|
||||
goto err;
|
||||
|
||||
writel(value, regs + B53_SRAB_WD_L);
|
||||
|
||||
ret = b53_srab_op(dev, page, reg, B53_SRAB_CMDSTAT_WRITE);
|
||||
|
||||
err:
|
||||
b53_srab_release_grant(dev);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int b53_srab_write16(struct b53_device *dev, u8 page, u8 reg,
|
||||
u16 value)
|
||||
{
|
||||
u8 __iomem *regs = dev->priv;
|
||||
int ret = 0;
|
||||
|
||||
ret = b53_srab_request_grant(dev);
|
||||
if (ret)
|
||||
goto err;
|
||||
|
||||
writel(value, regs + B53_SRAB_WD_L);
|
||||
|
||||
ret = b53_srab_op(dev, page, reg, B53_SRAB_CMDSTAT_WRITE);
|
||||
|
||||
err:
|
||||
b53_srab_release_grant(dev);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int b53_srab_write32(struct b53_device *dev, u8 page, u8 reg,
|
||||
u32 value)
|
||||
{
|
||||
u8 __iomem *regs = dev->priv;
|
||||
int ret = 0;
|
||||
|
||||
ret = b53_srab_request_grant(dev);
|
||||
if (ret)
|
||||
goto err;
|
||||
|
||||
writel(value, regs + B53_SRAB_WD_L);
|
||||
|
||||
ret = b53_srab_op(dev, page, reg, B53_SRAB_CMDSTAT_WRITE);
|
||||
|
||||
err:
|
||||
b53_srab_release_grant(dev);
|
||||
|
||||
return ret;
|
||||
|
||||
}
|
||||
|
||||
static int b53_srab_write48(struct b53_device *dev, u8 page, u8 reg,
|
||||
u64 value)
|
||||
{
|
||||
u8 __iomem *regs = dev->priv;
|
||||
int ret = 0;
|
||||
|
||||
ret = b53_srab_request_grant(dev);
|
||||
if (ret)
|
||||
goto err;
|
||||
|
||||
writel((u32)value, regs + B53_SRAB_WD_L);
|
||||
writel((u16)(value >> 32), regs + B53_SRAB_WD_H);
|
||||
|
||||
ret = b53_srab_op(dev, page, reg, B53_SRAB_CMDSTAT_WRITE);
|
||||
|
||||
err:
|
||||
b53_srab_release_grant(dev);
|
||||
|
||||
return ret;
|
||||
|
||||
}
|
||||
|
||||
static int b53_srab_write64(struct b53_device *dev, u8 page, u8 reg,
|
||||
u64 value)
|
||||
{
|
||||
u8 __iomem *regs = dev->priv;
|
||||
int ret = 0;
|
||||
|
||||
ret = b53_srab_request_grant(dev);
|
||||
if (ret)
|
||||
goto err;
|
||||
|
||||
writel((u32)value, regs + B53_SRAB_WD_L);
|
||||
writel((u32)(value >> 32), regs + B53_SRAB_WD_H);
|
||||
|
||||
ret = b53_srab_op(dev, page, reg, B53_SRAB_CMDSTAT_WRITE);
|
||||
|
||||
err:
|
||||
b53_srab_release_grant(dev);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static struct b53_io_ops b53_srab_ops = {
|
||||
.read8 = b53_srab_read8,
|
||||
.read16 = b53_srab_read16,
|
||||
.read32 = b53_srab_read32,
|
||||
.read48 = b53_srab_read48,
|
||||
.read64 = b53_srab_read64,
|
||||
.write8 = b53_srab_write8,
|
||||
.write16 = b53_srab_write16,
|
||||
.write32 = b53_srab_write32,
|
||||
.write48 = b53_srab_write48,
|
||||
.write64 = b53_srab_write64,
|
||||
};
|
||||
|
||||
static int b53_srab_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct b53_platform_data *pdata = pdev->dev.platform_data;
|
||||
struct b53_device *dev;
|
||||
|
||||
if (!pdata)
|
||||
return -EINVAL;
|
||||
|
||||
dev = b53_swconfig_switch_alloc(&pdev->dev, &b53_srab_ops, pdata->regs);
|
||||
if (!dev)
|
||||
return -ENOMEM;
|
||||
|
||||
if (pdata)
|
||||
dev->pdata = pdata;
|
||||
|
||||
platform_set_drvdata(pdev, dev);
|
||||
|
||||
return b53_swconfig_switch_register(dev);
|
||||
}
|
||||
|
||||
#if LINUX_VERSION_CODE < KERNEL_VERSION(6,11,0)
|
||||
static int b53_srab_remove(struct platform_device *pdev)
|
||||
#else
|
||||
static void b53_srab_remove(struct platform_device *pdev)
|
||||
#endif
|
||||
{
|
||||
struct b53_device *dev = platform_get_drvdata(pdev);
|
||||
|
||||
if (dev)
|
||||
b53_switch_remove(dev);
|
||||
|
||||
#if LINUX_VERSION_CODE < KERNEL_VERSION(6,11,0)
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
static struct platform_driver b53_srab_driver = {
|
||||
.probe = b53_srab_probe,
|
||||
.remove = b53_srab_remove,
|
||||
.driver = {
|
||||
.name = "b53-srab-switch",
|
||||
},
|
||||
};
|
||||
|
||||
module_platform_driver(b53_srab_driver);
|
||||
MODULE_AUTHOR("Hauke Mehrtens <hauke@hauke-m.de>");
|
||||
MODULE_DESCRIPTION("B53 Switch Register Access Bridge Registers (SRAB) access driver");
|
||||
MODULE_LICENSE("Dual BSD/GPL");
|
1370
6.12/target/linux/generic/files/drivers/net/phy/ip17xx.c
Normal file
1370
6.12/target/linux/generic/files/drivers/net/phy/ip17xx.c
Normal file
File diff suppressed because it is too large
Load diff
443
6.12/target/linux/generic/files/drivers/net/phy/psb6970.c
Normal file
443
6.12/target/linux/generic/files/drivers/net/phy/psb6970.c
Normal file
|
@ -0,0 +1,443 @@
|
|||
/*
|
||||
* Lantiq PSB6970 (Tantos) Switch driver
|
||||
*
|
||||
* Copyright (c) 2009,2010 Team Embedded.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License v2 as published by the
|
||||
* Free Software Foundation.
|
||||
*
|
||||
* The switch programming done in this driver follows the
|
||||
* "Ethernet Traffic Separation using VLAN" Application Note as
|
||||
* published by Lantiq.
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/netdevice.h>
|
||||
#include <linux/switch.h>
|
||||
#include <linux/phy.h>
|
||||
#include <linux/version.h>
|
||||
|
||||
#define PSB6970_MAX_VLANS 16
|
||||
#define PSB6970_NUM_PORTS 7
|
||||
#define PSB6970_DEFAULT_PORT_CPU 6
|
||||
#define PSB6970_IS_CPU_PORT(x) ((x) > 4)
|
||||
|
||||
#define PHYADDR(_reg) ((_reg >> 5) & 0xff), (_reg & 0x1f)
|
||||
|
||||
/* --- Identification --- */
|
||||
#define PSB6970_CI0 0x0100
|
||||
#define PSB6970_CI0_MASK 0x000f
|
||||
#define PSB6970_CI1 0x0101
|
||||
#define PSB6970_CI1_VAL 0x2599
|
||||
#define PSB6970_CI1_MASK 0xffff
|
||||
|
||||
/* --- VLAN filter table --- */
|
||||
#define PSB6970_VFxL(i) ((i)*2+0x10) /* VLAN Filter Low */
|
||||
#define PSB6970_VFxL_VV (1 << 15) /* VLAN_Valid */
|
||||
|
||||
#define PSB6970_VFxH(i) ((i)*2+0x11) /* VLAN Filter High */
|
||||
#define PSB6970_VFxH_TM_SHIFT 7 /* Tagged Member */
|
||||
|
||||
/* --- Port registers --- */
|
||||
#define PSB6970_EC(p) ((p)*0x20+2) /* Extended Control */
|
||||
#define PSB6970_EC_IFNTE (1 << 1) /* Input Force No Tag Enable */
|
||||
|
||||
#define PSB6970_PBVM(p) ((p)*0x20+3) /* Port Base VLAN Map */
|
||||
#define PSB6970_PBVM_VMCE (1 << 8)
|
||||
#define PSB6970_PBVM_AOVTP (1 << 9)
|
||||
#define PSB6970_PBVM_VSD (1 << 10)
|
||||
#define PSB6970_PBVM_VC (1 << 11) /* VID Check with VID table */
|
||||
#define PSB6970_PBVM_TBVE (1 << 13) /* Tag-Based VLAN enable */
|
||||
|
||||
#define PSB6970_DVID(p) ((p)*0x20+4) /* Default VLAN ID & Priority */
|
||||
|
||||
struct psb6970_priv {
|
||||
struct switch_dev dev;
|
||||
struct phy_device *phy;
|
||||
u16 (*read) (struct phy_device* phydev, int reg);
|
||||
void (*write) (struct phy_device* phydev, int reg, u16 val);
|
||||
struct mutex reg_mutex;
|
||||
|
||||
/* all fields below are cleared on reset */
|
||||
struct_group(psb6970_priv_volatile,
|
||||
bool vlan;
|
||||
u16 vlan_id[PSB6970_MAX_VLANS];
|
||||
u8 vlan_table[PSB6970_MAX_VLANS];
|
||||
u8 vlan_tagged;
|
||||
u16 pvid[PSB6970_NUM_PORTS];
|
||||
);
|
||||
};
|
||||
|
||||
#define to_psb6970(_dev) container_of(_dev, struct psb6970_priv, dev)
|
||||
|
||||
static u16 psb6970_mii_read(struct phy_device *phydev, int reg)
|
||||
{
|
||||
struct mii_bus *bus = phydev->mdio.bus;
|
||||
|
||||
return bus->read(bus, PHYADDR(reg));
|
||||
}
|
||||
|
||||
static void psb6970_mii_write(struct phy_device *phydev, int reg, u16 val)
|
||||
{
|
||||
struct mii_bus *bus = phydev->mdio.bus;
|
||||
|
||||
bus->write(bus, PHYADDR(reg), val);
|
||||
}
|
||||
|
||||
static int
|
||||
psb6970_set_vlan(struct switch_dev *dev, const struct switch_attr *attr,
|
||||
struct switch_val *val)
|
||||
{
|
||||
struct psb6970_priv *priv = to_psb6970(dev);
|
||||
priv->vlan = !!val->value.i;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
psb6970_get_vlan(struct switch_dev *dev, const struct switch_attr *attr,
|
||||
struct switch_val *val)
|
||||
{
|
||||
struct psb6970_priv *priv = to_psb6970(dev);
|
||||
val->value.i = priv->vlan;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int psb6970_set_pvid(struct switch_dev *dev, int port, int vlan)
|
||||
{
|
||||
struct psb6970_priv *priv = to_psb6970(dev);
|
||||
|
||||
/* make sure no invalid PVIDs get set */
|
||||
if (vlan >= dev->vlans)
|
||||
return -EINVAL;
|
||||
|
||||
priv->pvid[port] = vlan;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int psb6970_get_pvid(struct switch_dev *dev, int port, int *vlan)
|
||||
{
|
||||
struct psb6970_priv *priv = to_psb6970(dev);
|
||||
*vlan = priv->pvid[port];
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
psb6970_set_vid(struct switch_dev *dev, const struct switch_attr *attr,
|
||||
struct switch_val *val)
|
||||
{
|
||||
struct psb6970_priv *priv = to_psb6970(dev);
|
||||
priv->vlan_id[val->port_vlan] = val->value.i;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
psb6970_get_vid(struct switch_dev *dev, const struct switch_attr *attr,
|
||||
struct switch_val *val)
|
||||
{
|
||||
struct psb6970_priv *priv = to_psb6970(dev);
|
||||
val->value.i = priv->vlan_id[val->port_vlan];
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct switch_attr psb6970_globals[] = {
|
||||
{
|
||||
.type = SWITCH_TYPE_INT,
|
||||
.name = "enable_vlan",
|
||||
.description = "Enable VLAN mode",
|
||||
.set = psb6970_set_vlan,
|
||||
.get = psb6970_get_vlan,
|
||||
.max = 1},
|
||||
};
|
||||
|
||||
static struct switch_attr psb6970_port[] = {
|
||||
};
|
||||
|
||||
static struct switch_attr psb6970_vlan[] = {
|
||||
{
|
||||
.type = SWITCH_TYPE_INT,
|
||||
.name = "vid",
|
||||
.description = "VLAN ID (0-4094)",
|
||||
.set = psb6970_set_vid,
|
||||
.get = psb6970_get_vid,
|
||||
.max = 4094,
|
||||
},
|
||||
};
|
||||
|
||||
static int psb6970_get_ports(struct switch_dev *dev, struct switch_val *val)
|
||||
{
|
||||
struct psb6970_priv *priv = to_psb6970(dev);
|
||||
u8 ports = priv->vlan_table[val->port_vlan];
|
||||
int i;
|
||||
|
||||
val->len = 0;
|
||||
for (i = 0; i < PSB6970_NUM_PORTS; i++) {
|
||||
struct switch_port *p;
|
||||
|
||||
if (!(ports & (1 << i)))
|
||||
continue;
|
||||
|
||||
p = &val->value.ports[val->len++];
|
||||
p->id = i;
|
||||
if (priv->vlan_tagged & (1 << i))
|
||||
p->flags = (1 << SWITCH_PORT_FLAG_TAGGED);
|
||||
else
|
||||
p->flags = 0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int psb6970_set_ports(struct switch_dev *dev, struct switch_val *val)
|
||||
{
|
||||
struct psb6970_priv *priv = to_psb6970(dev);
|
||||
u8 *vt = &priv->vlan_table[val->port_vlan];
|
||||
int i, j;
|
||||
|
||||
*vt = 0;
|
||||
for (i = 0; i < val->len; i++) {
|
||||
struct switch_port *p = &val->value.ports[i];
|
||||
|
||||
if (p->flags & (1 << SWITCH_PORT_FLAG_TAGGED))
|
||||
priv->vlan_tagged |= (1 << p->id);
|
||||
else {
|
||||
priv->vlan_tagged &= ~(1 << p->id);
|
||||
priv->pvid[p->id] = val->port_vlan;
|
||||
|
||||
/* make sure that an untagged port does not
|
||||
* appear in other vlans */
|
||||
for (j = 0; j < PSB6970_MAX_VLANS; j++) {
|
||||
if (j == val->port_vlan)
|
||||
continue;
|
||||
priv->vlan_table[j] &= ~(1 << p->id);
|
||||
}
|
||||
}
|
||||
|
||||
*vt |= 1 << p->id;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int psb6970_hw_apply(struct switch_dev *dev)
|
||||
{
|
||||
struct psb6970_priv *priv = to_psb6970(dev);
|
||||
int i, j;
|
||||
|
||||
mutex_lock(&priv->reg_mutex);
|
||||
|
||||
if (priv->vlan) {
|
||||
/* into the vlan translation unit */
|
||||
for (j = 0; j < PSB6970_MAX_VLANS; j++) {
|
||||
u8 vp = priv->vlan_table[j];
|
||||
|
||||
if (vp) {
|
||||
priv->write(priv->phy, PSB6970_VFxL(j),
|
||||
PSB6970_VFxL_VV | priv->vlan_id[j]);
|
||||
priv->write(priv->phy, PSB6970_VFxH(j),
|
||||
((vp & priv->
|
||||
vlan_tagged) <<
|
||||
PSB6970_VFxH_TM_SHIFT) | vp);
|
||||
} else /* clear VLAN Valid flag for unused vlans */
|
||||
priv->write(priv->phy, PSB6970_VFxL(j), 0);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/* update the port destination mask registers and tag settings */
|
||||
for (i = 0; i < PSB6970_NUM_PORTS; i++) {
|
||||
int dvid = 1, pbvm = 0x7f | PSB6970_PBVM_VSD, ec = 0;
|
||||
|
||||
if (priv->vlan) {
|
||||
ec = PSB6970_EC_IFNTE;
|
||||
dvid = priv->vlan_id[priv->pvid[i]];
|
||||
pbvm |= PSB6970_PBVM_TBVE | PSB6970_PBVM_VMCE;
|
||||
|
||||
if ((i << 1) & priv->vlan_tagged)
|
||||
pbvm |= PSB6970_PBVM_AOVTP | PSB6970_PBVM_VC;
|
||||
}
|
||||
|
||||
priv->write(priv->phy, PSB6970_PBVM(i), pbvm);
|
||||
|
||||
if (!PSB6970_IS_CPU_PORT(i)) {
|
||||
priv->write(priv->phy, PSB6970_EC(i), ec);
|
||||
priv->write(priv->phy, PSB6970_DVID(i), dvid);
|
||||
}
|
||||
}
|
||||
|
||||
mutex_unlock(&priv->reg_mutex);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int psb6970_reset_switch(struct switch_dev *dev)
|
||||
{
|
||||
struct psb6970_priv *priv = to_psb6970(dev);
|
||||
int i;
|
||||
|
||||
mutex_lock(&priv->reg_mutex);
|
||||
|
||||
memset(&priv->psb6970_priv_volatile, 0,
|
||||
sizeof(priv->psb6970_priv_volatile));
|
||||
|
||||
for (i = 0; i < PSB6970_MAX_VLANS; i++)
|
||||
priv->vlan_id[i] = i;
|
||||
|
||||
mutex_unlock(&priv->reg_mutex);
|
||||
|
||||
return psb6970_hw_apply(dev);
|
||||
}
|
||||
|
||||
static const struct switch_dev_ops psb6970_ops = {
|
||||
.attr_global = {
|
||||
.attr = psb6970_globals,
|
||||
.n_attr = ARRAY_SIZE(psb6970_globals),
|
||||
},
|
||||
.attr_port = {
|
||||
.attr = psb6970_port,
|
||||
.n_attr = ARRAY_SIZE(psb6970_port),
|
||||
},
|
||||
.attr_vlan = {
|
||||
.attr = psb6970_vlan,
|
||||
.n_attr = ARRAY_SIZE(psb6970_vlan),
|
||||
},
|
||||
.get_port_pvid = psb6970_get_pvid,
|
||||
.set_port_pvid = psb6970_set_pvid,
|
||||
.get_vlan_ports = psb6970_get_ports,
|
||||
.set_vlan_ports = psb6970_set_ports,
|
||||
.apply_config = psb6970_hw_apply,
|
||||
.reset_switch = psb6970_reset_switch,
|
||||
};
|
||||
|
||||
static int psb6970_config_init(struct phy_device *pdev)
|
||||
{
|
||||
struct psb6970_priv *priv;
|
||||
struct switch_dev *swdev;
|
||||
int ret;
|
||||
|
||||
priv = kzalloc(sizeof(struct psb6970_priv), GFP_KERNEL);
|
||||
if (priv == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
priv->phy = pdev;
|
||||
|
||||
if (pdev->mdio.addr == 0)
|
||||
printk(KERN_INFO "%s: psb6970 switch driver attached.\n",
|
||||
pdev->attached_dev->name);
|
||||
|
||||
if (pdev->mdio.addr != 0) {
|
||||
kfree(priv);
|
||||
return 0;
|
||||
}
|
||||
|
||||
linkmode_zero(pdev->supported);
|
||||
linkmode_set_bit(ETHTOOL_LINK_MODE_100baseT_Full_BIT, pdev->supported);
|
||||
linkmode_copy(pdev->advertising, pdev->supported);
|
||||
|
||||
mutex_init(&priv->reg_mutex);
|
||||
priv->read = psb6970_mii_read;
|
||||
priv->write = psb6970_mii_write;
|
||||
|
||||
pdev->priv = priv;
|
||||
|
||||
swdev = &priv->dev;
|
||||
swdev->cpu_port = PSB6970_DEFAULT_PORT_CPU;
|
||||
swdev->ops = &psb6970_ops;
|
||||
|
||||
swdev->name = "Lantiq PSB6970";
|
||||
swdev->vlans = PSB6970_MAX_VLANS;
|
||||
swdev->ports = PSB6970_NUM_PORTS;
|
||||
|
||||
if ((ret = register_switch(&priv->dev, pdev->attached_dev)) < 0) {
|
||||
kfree(priv);
|
||||
goto done;
|
||||
}
|
||||
|
||||
ret = psb6970_reset_switch(&priv->dev);
|
||||
if (ret) {
|
||||
kfree(priv);
|
||||
goto done;
|
||||
}
|
||||
|
||||
done:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int psb6970_read_status(struct phy_device *phydev)
|
||||
{
|
||||
phydev->speed = SPEED_100;
|
||||
phydev->duplex = DUPLEX_FULL;
|
||||
phydev->link = 1;
|
||||
|
||||
phydev->state = PHY_RUNNING;
|
||||
netif_carrier_on(phydev->attached_dev);
|
||||
phydev->adjust_link(phydev->attached_dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int psb6970_config_aneg(struct phy_device *phydev)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int psb6970_probe(struct phy_device *pdev)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void psb6970_remove(struct phy_device *pdev)
|
||||
{
|
||||
struct psb6970_priv *priv = pdev->priv;
|
||||
|
||||
if (!priv)
|
||||
return;
|
||||
|
||||
if (pdev->mdio.addr == 0)
|
||||
unregister_switch(&priv->dev);
|
||||
kfree(priv);
|
||||
}
|
||||
|
||||
static int psb6970_fixup(struct phy_device *dev)
|
||||
{
|
||||
struct mii_bus *bus = dev->mdio.bus;
|
||||
u16 reg;
|
||||
|
||||
/* look for the switch on the bus */
|
||||
reg = bus->read(bus, PHYADDR(PSB6970_CI1)) & PSB6970_CI1_MASK;
|
||||
if (reg != PSB6970_CI1_VAL)
|
||||
return 0;
|
||||
|
||||
dev->phy_id = (reg << 16);
|
||||
dev->phy_id |= bus->read(bus, PHYADDR(PSB6970_CI0)) & PSB6970_CI0_MASK;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct phy_driver psb6970_driver = {
|
||||
.name = "Lantiq PSB6970",
|
||||
.phy_id = PSB6970_CI1_VAL << 16,
|
||||
.phy_id_mask = 0xffff0000,
|
||||
.features = PHY_BASIC_FEATURES,
|
||||
.probe = psb6970_probe,
|
||||
.remove = psb6970_remove,
|
||||
.config_init = &psb6970_config_init,
|
||||
.config_aneg = &psb6970_config_aneg,
|
||||
.read_status = &psb6970_read_status,
|
||||
};
|
||||
|
||||
int __init psb6970_init(void)
|
||||
{
|
||||
phy_register_fixup_for_id(PHY_ANY_ID, psb6970_fixup);
|
||||
return phy_driver_register(&psb6970_driver, THIS_MODULE);
|
||||
}
|
||||
|
||||
module_init(psb6970_init);
|
||||
|
||||
void __exit psb6970_exit(void)
|
||||
{
|
||||
phy_driver_unregister(&psb6970_driver);
|
||||
}
|
||||
|
||||
module_exit(psb6970_exit);
|
||||
|
||||
MODULE_DESCRIPTION("Lantiq PSB6970 Switch");
|
||||
MODULE_AUTHOR("Ithamar R. Adema <ithamar.adema@team-embedded.nl>");
|
||||
MODULE_LICENSE("GPL");
|
1063
6.12/target/linux/generic/files/drivers/net/phy/rtl8306.c
Normal file
1063
6.12/target/linux/generic/files/drivers/net/phy/rtl8306.c
Normal file
File diff suppressed because it is too large
Load diff
1625
6.12/target/linux/generic/files/drivers/net/phy/rtl8366_smi.c
Normal file
1625
6.12/target/linux/generic/files/drivers/net/phy/rtl8366_smi.c
Normal file
File diff suppressed because it is too large
Load diff
171
6.12/target/linux/generic/files/drivers/net/phy/rtl8366_smi.h
Normal file
171
6.12/target/linux/generic/files/drivers/net/phy/rtl8366_smi.h
Normal file
|
@ -0,0 +1,171 @@
|
|||
/*
|
||||
* Realtek RTL8366 SMI interface driver defines
|
||||
*
|
||||
* Copyright (C) 2009-2010 Gabor Juhos <juhosg@openwrt.org>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 as published
|
||||
* by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#ifndef _RTL8366_SMI_H
|
||||
#define _RTL8366_SMI_H
|
||||
|
||||
#include <linux/phy.h>
|
||||
#include <linux/switch.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/reset.h>
|
||||
|
||||
struct rtl8366_smi_ops;
|
||||
struct rtl8366_vlan_ops;
|
||||
struct mii_bus;
|
||||
struct dentry;
|
||||
struct inode;
|
||||
struct file;
|
||||
|
||||
typedef enum rtl8367b_chip_e {
|
||||
RTL8367B_CHIP_UNKNOWN,
|
||||
/* Family B */
|
||||
RTL8367B_CHIP_RTL8367RB,
|
||||
RTL8367B_CHIP_RTL8367R_VB, /* chip with exception in extif assignment */
|
||||
/* Family C */
|
||||
RTL8367B_CHIP_RTL8367RB_VB,
|
||||
RTL8367B_CHIP_RTL8367S,
|
||||
/* Family D */
|
||||
RTL8367B_CHIP_RTL8367S_VB /* chip with exception in extif assignment */
|
||||
} rtl8367b_chip_t;
|
||||
|
||||
struct rtl8366_mib_counter {
|
||||
unsigned base;
|
||||
unsigned offset;
|
||||
unsigned length;
|
||||
const char *name;
|
||||
};
|
||||
|
||||
struct rtl8366_smi {
|
||||
struct device *parent;
|
||||
unsigned int gpio_sda;
|
||||
unsigned int gpio_sck;
|
||||
void (*hw_reset)(struct rtl8366_smi *smi, bool active);
|
||||
unsigned int clk_delay; /* ns */
|
||||
u8 cmd_read;
|
||||
u8 cmd_write;
|
||||
spinlock_t lock;
|
||||
struct mii_bus *mii_bus;
|
||||
int mii_irq[PHY_MAX_ADDR];
|
||||
struct switch_dev sw_dev;
|
||||
|
||||
unsigned int cpu_port;
|
||||
unsigned int num_ports;
|
||||
unsigned int num_vlan_mc;
|
||||
unsigned int num_mib_counters;
|
||||
struct rtl8366_mib_counter *mib_counters;
|
||||
|
||||
struct rtl8366_smi_ops *ops;
|
||||
|
||||
int vlan_enabled;
|
||||
int vlan4k_enabled;
|
||||
|
||||
char buf[4096];
|
||||
|
||||
struct reset_control *reset;
|
||||
|
||||
#ifdef CONFIG_RTL8366_SMI_DEBUG_FS
|
||||
struct dentry *debugfs_root;
|
||||
u16 dbg_reg;
|
||||
u8 dbg_vlan_4k_page;
|
||||
#endif
|
||||
u32 phy_id;
|
||||
rtl8367b_chip_t rtl8367b_chip;
|
||||
struct mii_bus *ext_mbus;
|
||||
struct rtl8366_vlan_mc *emu_vlanmc;
|
||||
};
|
||||
|
||||
struct rtl8366_vlan_mc {
|
||||
u16 vid;
|
||||
u16 untag;
|
||||
u16 member;
|
||||
u8 fid;
|
||||
u8 priority;
|
||||
};
|
||||
|
||||
struct rtl8366_vlan_4k {
|
||||
u16 vid;
|
||||
u16 untag;
|
||||
u16 member;
|
||||
u8 fid;
|
||||
};
|
||||
|
||||
struct rtl8366_smi_ops {
|
||||
int (*detect)(struct rtl8366_smi *smi);
|
||||
int (*reset_chip)(struct rtl8366_smi *smi);
|
||||
int (*setup)(struct rtl8366_smi *smi);
|
||||
|
||||
int (*mii_read)(struct mii_bus *bus, int addr, int reg);
|
||||
int (*mii_write)(struct mii_bus *bus, int addr, int reg, u16 val);
|
||||
|
||||
int (*get_vlan_mc)(struct rtl8366_smi *smi, u32 index,
|
||||
struct rtl8366_vlan_mc *vlanmc);
|
||||
int (*set_vlan_mc)(struct rtl8366_smi *smi, u32 index,
|
||||
const struct rtl8366_vlan_mc *vlanmc);
|
||||
int (*get_vlan_4k)(struct rtl8366_smi *smi, u32 vid,
|
||||
struct rtl8366_vlan_4k *vlan4k);
|
||||
int (*set_vlan_4k)(struct rtl8366_smi *smi,
|
||||
const struct rtl8366_vlan_4k *vlan4k);
|
||||
int (*get_mc_index)(struct rtl8366_smi *smi, int port, int *val);
|
||||
int (*set_mc_index)(struct rtl8366_smi *smi, int port, int index);
|
||||
int (*get_mib_counter)(struct rtl8366_smi *smi, int counter,
|
||||
int port, unsigned long long *val);
|
||||
int (*is_vlan_valid)(struct rtl8366_smi *smi, unsigned vlan);
|
||||
int (*enable_vlan)(struct rtl8366_smi *smi, int enable);
|
||||
int (*enable_vlan4k)(struct rtl8366_smi *smi, int enable);
|
||||
int (*enable_port)(struct rtl8366_smi *smi, int port, int enable);
|
||||
};
|
||||
|
||||
struct rtl8366_smi *rtl8366_smi_alloc(struct device *parent);
|
||||
int rtl8366_smi_init(struct rtl8366_smi *smi);
|
||||
void rtl8366_smi_cleanup(struct rtl8366_smi *smi);
|
||||
int rtl8366_smi_write_reg(struct rtl8366_smi *smi, u32 addr, u32 data);
|
||||
int rtl8366_smi_write_reg_noack(struct rtl8366_smi *smi, u32 addr, u32 data);
|
||||
int rtl8366_smi_read_reg(struct rtl8366_smi *smi, u32 addr, u32 *data);
|
||||
int rtl8366_smi_rmwr(struct rtl8366_smi *smi, u32 addr, u32 mask, u32 data);
|
||||
|
||||
#ifdef CONFIG_RTL8366_SMI_DEBUG_FS
|
||||
int rtl8366_debugfs_open(struct inode *inode, struct file *file);
|
||||
#endif
|
||||
|
||||
static inline struct rtl8366_smi *sw_to_rtl8366_smi(struct switch_dev *sw)
|
||||
{
|
||||
return container_of(sw, struct rtl8366_smi, sw_dev);
|
||||
}
|
||||
|
||||
int rtl8366_sw_reset_switch(struct switch_dev *dev);
|
||||
int rtl8366_sw_get_port_pvid(struct switch_dev *dev, int port, int *val);
|
||||
int rtl8366_sw_set_port_pvid(struct switch_dev *dev, int port, int val);
|
||||
int rtl8366_sw_get_port_mib(struct switch_dev *dev,
|
||||
const struct switch_attr *attr,
|
||||
struct switch_val *val);
|
||||
int rtl8366_sw_get_vlan_info(struct switch_dev *dev,
|
||||
const struct switch_attr *attr,
|
||||
struct switch_val *val);
|
||||
int rtl8366_sw_get_vlan_fid(struct switch_dev *dev,
|
||||
const struct switch_attr *attr,
|
||||
struct switch_val *val);
|
||||
int rtl8366_sw_set_vlan_fid(struct switch_dev *dev,
|
||||
const struct switch_attr *attr,
|
||||
struct switch_val *val);
|
||||
int rtl8366_sw_get_vlan_ports(struct switch_dev *dev, struct switch_val *val);
|
||||
int rtl8366_sw_set_vlan_ports(struct switch_dev *dev, struct switch_val *val);
|
||||
int rtl8366_sw_get_vlan_enable(struct switch_dev *dev,
|
||||
const struct switch_attr *attr,
|
||||
struct switch_val *val);
|
||||
int rtl8366_sw_set_vlan_enable(struct switch_dev *dev,
|
||||
const struct switch_attr *attr,
|
||||
struct switch_val *val);
|
||||
int rtl8366_sw_get_port_stats(struct switch_dev *dev, int port,
|
||||
struct switch_port_stats *stats,
|
||||
int txb_id, int rxb_id);
|
||||
|
||||
struct rtl8366_smi* rtl8366_smi_probe(struct platform_device *pdev);
|
||||
|
||||
#endif /* _RTL8366_SMI_H */
|
1538
6.12/target/linux/generic/files/drivers/net/phy/rtl8366rb.c
Normal file
1538
6.12/target/linux/generic/files/drivers/net/phy/rtl8366rb.c
Normal file
File diff suppressed because it is too large
Load diff
1326
6.12/target/linux/generic/files/drivers/net/phy/rtl8366s.c
Normal file
1326
6.12/target/linux/generic/files/drivers/net/phy/rtl8366s.c
Normal file
File diff suppressed because it is too large
Load diff
1868
6.12/target/linux/generic/files/drivers/net/phy/rtl8367.c
Normal file
1868
6.12/target/linux/generic/files/drivers/net/phy/rtl8367.c
Normal file
File diff suppressed because it is too large
Load diff
1658
6.12/target/linux/generic/files/drivers/net/phy/rtl8367b.c
Normal file
1658
6.12/target/linux/generic/files/drivers/net/phy/rtl8367b.c
Normal file
File diff suppressed because it is too large
Load diff
1242
6.12/target/linux/generic/files/drivers/net/phy/swconfig.c
Normal file
1242
6.12/target/linux/generic/files/drivers/net/phy/swconfig.c
Normal file
File diff suppressed because it is too large
Load diff
555
6.12/target/linux/generic/files/drivers/net/phy/swconfig_leds.c
Normal file
555
6.12/target/linux/generic/files/drivers/net/phy/swconfig_leds.c
Normal file
|
@ -0,0 +1,555 @@
|
|||
/*
|
||||
* swconfig_led.c: LED trigger support for the switch configuration API
|
||||
*
|
||||
* Copyright (C) 2011 Gabor Juhos <juhosg@openwrt.org>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifdef CONFIG_SWCONFIG_LEDS
|
||||
|
||||
#include <linux/leds.h>
|
||||
#include <linux/ctype.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/workqueue.h>
|
||||
|
||||
#define SWCONFIG_LED_TIMER_INTERVAL (HZ / 10)
|
||||
#define SWCONFIG_LED_NUM_PORTS 32
|
||||
|
||||
#define SWCONFIG_LED_PORT_SPEED_NA 0x01 /* unknown speed */
|
||||
#define SWCONFIG_LED_PORT_SPEED_10 0x02 /* 10 Mbps */
|
||||
#define SWCONFIG_LED_PORT_SPEED_100 0x04 /* 100 Mbps */
|
||||
#define SWCONFIG_LED_PORT_SPEED_1000 0x08 /* 1000 Mbps */
|
||||
#define SWCONFIG_LED_PORT_SPEED_ALL (SWCONFIG_LED_PORT_SPEED_NA | \
|
||||
SWCONFIG_LED_PORT_SPEED_10 | \
|
||||
SWCONFIG_LED_PORT_SPEED_100 | \
|
||||
SWCONFIG_LED_PORT_SPEED_1000)
|
||||
|
||||
#define SWCONFIG_LED_MODE_LINK 0x01
|
||||
#define SWCONFIG_LED_MODE_TX 0x02
|
||||
#define SWCONFIG_LED_MODE_RX 0x04
|
||||
#define SWCONFIG_LED_MODE_TXRX (SWCONFIG_LED_MODE_TX | \
|
||||
SWCONFIG_LED_MODE_RX)
|
||||
#define SWCONFIG_LED_MODE_ALL (SWCONFIG_LED_MODE_LINK | \
|
||||
SWCONFIG_LED_MODE_TX | \
|
||||
SWCONFIG_LED_MODE_RX)
|
||||
|
||||
struct switch_led_trigger {
|
||||
struct led_trigger trig;
|
||||
struct switch_dev *swdev;
|
||||
|
||||
struct delayed_work sw_led_work;
|
||||
u32 port_mask;
|
||||
u32 port_link;
|
||||
unsigned long long port_tx_traffic[SWCONFIG_LED_NUM_PORTS];
|
||||
unsigned long long port_rx_traffic[SWCONFIG_LED_NUM_PORTS];
|
||||
u8 link_speed[SWCONFIG_LED_NUM_PORTS];
|
||||
};
|
||||
|
||||
struct swconfig_trig_data {
|
||||
struct led_classdev *led_cdev;
|
||||
struct switch_dev *swdev;
|
||||
|
||||
rwlock_t lock;
|
||||
u32 port_mask;
|
||||
|
||||
bool prev_link;
|
||||
unsigned long prev_traffic;
|
||||
enum led_brightness prev_brightness;
|
||||
u8 mode;
|
||||
u8 speed_mask;
|
||||
};
|
||||
|
||||
static void
|
||||
swconfig_trig_set_brightness(struct swconfig_trig_data *trig_data,
|
||||
enum led_brightness brightness)
|
||||
{
|
||||
led_set_brightness(trig_data->led_cdev, brightness);
|
||||
trig_data->prev_brightness = brightness;
|
||||
}
|
||||
|
||||
static void
|
||||
swconfig_trig_update_port_mask(struct led_trigger *trigger)
|
||||
{
|
||||
struct list_head *entry;
|
||||
struct switch_led_trigger *sw_trig;
|
||||
u32 port_mask;
|
||||
|
||||
if (!trigger)
|
||||
return;
|
||||
|
||||
sw_trig = (void *) trigger;
|
||||
|
||||
port_mask = 0;
|
||||
spin_lock(&trigger->leddev_list_lock);
|
||||
list_for_each(entry, &trigger->led_cdevs) {
|
||||
struct led_classdev *led_cdev;
|
||||
struct swconfig_trig_data *trig_data;
|
||||
|
||||
led_cdev = list_entry(entry, struct led_classdev, trig_list);
|
||||
trig_data = led_cdev->trigger_data;
|
||||
if (trig_data) {
|
||||
read_lock(&trig_data->lock);
|
||||
port_mask |= trig_data->port_mask;
|
||||
read_unlock(&trig_data->lock);
|
||||
}
|
||||
}
|
||||
spin_unlock(&trigger->leddev_list_lock);
|
||||
|
||||
sw_trig->port_mask = port_mask;
|
||||
|
||||
if (port_mask)
|
||||
schedule_delayed_work(&sw_trig->sw_led_work,
|
||||
SWCONFIG_LED_TIMER_INTERVAL);
|
||||
else
|
||||
cancel_delayed_work_sync(&sw_trig->sw_led_work);
|
||||
}
|
||||
|
||||
static ssize_t
|
||||
swconfig_trig_port_mask_store(struct device *dev, struct device_attribute *attr,
|
||||
const char *buf, size_t size)
|
||||
{
|
||||
struct led_classdev *led_cdev = dev_get_drvdata(dev);
|
||||
struct swconfig_trig_data *trig_data = led_cdev->trigger_data;
|
||||
unsigned long port_mask;
|
||||
int ret;
|
||||
bool changed;
|
||||
|
||||
ret = kstrtoul(buf, 0, &port_mask);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
write_lock(&trig_data->lock);
|
||||
changed = (trig_data->port_mask != port_mask);
|
||||
trig_data->port_mask = port_mask;
|
||||
write_unlock(&trig_data->lock);
|
||||
|
||||
if (changed) {
|
||||
if (port_mask == 0)
|
||||
swconfig_trig_set_brightness(trig_data, LED_OFF);
|
||||
|
||||
swconfig_trig_update_port_mask(led_cdev->trigger);
|
||||
}
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
static ssize_t
|
||||
swconfig_trig_port_mask_show(struct device *dev, struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
struct led_classdev *led_cdev = dev_get_drvdata(dev);
|
||||
struct swconfig_trig_data *trig_data = led_cdev->trigger_data;
|
||||
u32 port_mask;
|
||||
|
||||
read_lock(&trig_data->lock);
|
||||
port_mask = trig_data->port_mask;
|
||||
read_unlock(&trig_data->lock);
|
||||
|
||||
sprintf(buf, "%#x\n", port_mask);
|
||||
|
||||
return strlen(buf) + 1;
|
||||
}
|
||||
|
||||
static DEVICE_ATTR(port_mask, 0644, swconfig_trig_port_mask_show,
|
||||
swconfig_trig_port_mask_store);
|
||||
|
||||
/* speed_mask file handler - display value */
|
||||
static ssize_t swconfig_trig_speed_mask_show(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
struct led_classdev *led_cdev = dev_get_drvdata(dev);
|
||||
struct swconfig_trig_data *trig_data = led_cdev->trigger_data;
|
||||
u8 speed_mask;
|
||||
|
||||
read_lock(&trig_data->lock);
|
||||
speed_mask = trig_data->speed_mask;
|
||||
read_unlock(&trig_data->lock);
|
||||
|
||||
sprintf(buf, "%#x\n", speed_mask);
|
||||
|
||||
return strlen(buf) + 1;
|
||||
}
|
||||
|
||||
/* speed_mask file handler - store value */
|
||||
static ssize_t swconfig_trig_speed_mask_store(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
const char *buf, size_t size)
|
||||
{
|
||||
struct led_classdev *led_cdev = dev_get_drvdata(dev);
|
||||
struct swconfig_trig_data *trig_data = led_cdev->trigger_data;
|
||||
u8 speed_mask;
|
||||
int ret;
|
||||
|
||||
ret = kstrtou8(buf, 0, &speed_mask);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
write_lock(&trig_data->lock);
|
||||
trig_data->speed_mask = speed_mask & SWCONFIG_LED_PORT_SPEED_ALL;
|
||||
write_unlock(&trig_data->lock);
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
/* speed_mask special file */
|
||||
static DEVICE_ATTR(speed_mask, 0644, swconfig_trig_speed_mask_show,
|
||||
swconfig_trig_speed_mask_store);
|
||||
|
||||
static ssize_t swconfig_trig_mode_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct led_classdev *led_cdev = dev_get_drvdata(dev);
|
||||
struct swconfig_trig_data *trig_data = led_cdev->trigger_data;
|
||||
u8 mode;
|
||||
|
||||
read_lock(&trig_data->lock);
|
||||
mode = trig_data->mode;
|
||||
read_unlock(&trig_data->lock);
|
||||
|
||||
if (mode == 0) {
|
||||
strcpy(buf, "none\n");
|
||||
} else {
|
||||
if (mode & SWCONFIG_LED_MODE_LINK)
|
||||
strcat(buf, "link ");
|
||||
if (mode & SWCONFIG_LED_MODE_TX)
|
||||
strcat(buf, "tx ");
|
||||
if (mode & SWCONFIG_LED_MODE_RX)
|
||||
strcat(buf, "rx ");
|
||||
strcat(buf, "\n");
|
||||
}
|
||||
|
||||
return strlen(buf)+1;
|
||||
}
|
||||
|
||||
static ssize_t swconfig_trig_mode_store(struct device *dev,
|
||||
struct device_attribute *attr, const char *buf, size_t size)
|
||||
{
|
||||
struct led_classdev *led_cdev = dev_get_drvdata(dev);
|
||||
struct swconfig_trig_data *trig_data = led_cdev->trigger_data;
|
||||
char copybuf[128];
|
||||
int new_mode = -1;
|
||||
char *p, *token;
|
||||
|
||||
/* take a copy since we don't want to trash the inbound buffer when using strsep */
|
||||
strncpy(copybuf, buf, sizeof(copybuf));
|
||||
copybuf[sizeof(copybuf) - 1] = 0;
|
||||
p = copybuf;
|
||||
|
||||
while ((token = strsep(&p, " \t\n")) != NULL) {
|
||||
if (!*token)
|
||||
continue;
|
||||
|
||||
if (new_mode < 0)
|
||||
new_mode = 0;
|
||||
|
||||
if (!strcmp(token, "none"))
|
||||
new_mode = 0;
|
||||
else if (!strcmp(token, "tx"))
|
||||
new_mode |= SWCONFIG_LED_MODE_TX;
|
||||
else if (!strcmp(token, "rx"))
|
||||
new_mode |= SWCONFIG_LED_MODE_RX;
|
||||
else if (!strcmp(token, "link"))
|
||||
new_mode |= SWCONFIG_LED_MODE_LINK;
|
||||
else
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (new_mode < 0)
|
||||
return -EINVAL;
|
||||
|
||||
write_lock(&trig_data->lock);
|
||||
trig_data->mode = (u8)new_mode;
|
||||
write_unlock(&trig_data->lock);
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
/* mode special file */
|
||||
static DEVICE_ATTR(mode, 0644, swconfig_trig_mode_show,
|
||||
swconfig_trig_mode_store);
|
||||
|
||||
static int
|
||||
swconfig_trig_activate(struct led_classdev *led_cdev)
|
||||
{
|
||||
struct switch_led_trigger *sw_trig;
|
||||
struct swconfig_trig_data *trig_data;
|
||||
int err;
|
||||
|
||||
trig_data = kzalloc(sizeof(struct swconfig_trig_data), GFP_KERNEL);
|
||||
if (!trig_data)
|
||||
return -ENOMEM;
|
||||
|
||||
sw_trig = (void *) led_cdev->trigger;
|
||||
|
||||
rwlock_init(&trig_data->lock);
|
||||
trig_data->led_cdev = led_cdev;
|
||||
trig_data->swdev = sw_trig->swdev;
|
||||
trig_data->speed_mask = SWCONFIG_LED_PORT_SPEED_ALL;
|
||||
trig_data->mode = SWCONFIG_LED_MODE_ALL;
|
||||
led_cdev->trigger_data = trig_data;
|
||||
|
||||
err = device_create_file(led_cdev->dev, &dev_attr_port_mask);
|
||||
if (err)
|
||||
goto err_free;
|
||||
|
||||
err = device_create_file(led_cdev->dev, &dev_attr_speed_mask);
|
||||
if (err)
|
||||
goto err_dev_free;
|
||||
|
||||
err = device_create_file(led_cdev->dev, &dev_attr_mode);
|
||||
if (err)
|
||||
goto err_mode_free;
|
||||
|
||||
return 0;
|
||||
|
||||
err_mode_free:
|
||||
device_remove_file(led_cdev->dev, &dev_attr_speed_mask);
|
||||
|
||||
err_dev_free:
|
||||
device_remove_file(led_cdev->dev, &dev_attr_port_mask);
|
||||
|
||||
err_free:
|
||||
led_cdev->trigger_data = NULL;
|
||||
kfree(trig_data);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static void
|
||||
swconfig_trig_deactivate(struct led_classdev *led_cdev)
|
||||
{
|
||||
struct swconfig_trig_data *trig_data;
|
||||
|
||||
swconfig_trig_update_port_mask(led_cdev->trigger);
|
||||
|
||||
trig_data = (void *) led_cdev->trigger_data;
|
||||
if (trig_data) {
|
||||
device_remove_file(led_cdev->dev, &dev_attr_port_mask);
|
||||
device_remove_file(led_cdev->dev, &dev_attr_speed_mask);
|
||||
device_remove_file(led_cdev->dev, &dev_attr_mode);
|
||||
kfree(trig_data);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* link off -> led off (can't be any other reason to turn it on)
|
||||
* link on:
|
||||
* mode link: led on by default only if speed matches, else off
|
||||
* mode txrx: blink only if speed matches, else off
|
||||
*/
|
||||
static void
|
||||
swconfig_trig_led_event(struct switch_led_trigger *sw_trig,
|
||||
struct led_classdev *led_cdev)
|
||||
{
|
||||
struct swconfig_trig_data *trig_data;
|
||||
u32 port_mask;
|
||||
bool link;
|
||||
u8 speed_mask, mode;
|
||||
enum led_brightness led_base, led_blink;
|
||||
|
||||
trig_data = led_cdev->trigger_data;
|
||||
if (!trig_data)
|
||||
return;
|
||||
|
||||
read_lock(&trig_data->lock);
|
||||
port_mask = trig_data->port_mask;
|
||||
speed_mask = trig_data->speed_mask;
|
||||
mode = trig_data->mode;
|
||||
read_unlock(&trig_data->lock);
|
||||
|
||||
link = !!(sw_trig->port_link & port_mask);
|
||||
if (!link) {
|
||||
if (trig_data->prev_brightness != LED_OFF)
|
||||
swconfig_trig_set_brightness(trig_data, LED_OFF); /* and stop */
|
||||
}
|
||||
else {
|
||||
unsigned long traffic;
|
||||
int speedok; /* link speed flag */
|
||||
int i;
|
||||
|
||||
led_base = LED_FULL;
|
||||
led_blink = LED_OFF;
|
||||
traffic = 0;
|
||||
speedok = 0;
|
||||
for (i = 0; i < SWCONFIG_LED_NUM_PORTS; i++) {
|
||||
if (port_mask & (1 << i)) {
|
||||
if (sw_trig->link_speed[i] & speed_mask) {
|
||||
traffic += ((mode & SWCONFIG_LED_MODE_TX) ?
|
||||
sw_trig->port_tx_traffic[i] : 0) +
|
||||
((mode & SWCONFIG_LED_MODE_RX) ?
|
||||
sw_trig->port_rx_traffic[i] : 0);
|
||||
speedok = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (speedok) {
|
||||
/* At least one port speed matches speed_mask */
|
||||
if (!(mode & SWCONFIG_LED_MODE_LINK)) {
|
||||
led_base = LED_OFF;
|
||||
led_blink = LED_FULL;
|
||||
}
|
||||
|
||||
if (trig_data->prev_brightness != led_base)
|
||||
swconfig_trig_set_brightness(trig_data,
|
||||
led_base);
|
||||
else if (traffic != trig_data->prev_traffic)
|
||||
swconfig_trig_set_brightness(trig_data,
|
||||
led_blink);
|
||||
} else if (trig_data->prev_brightness != LED_OFF)
|
||||
swconfig_trig_set_brightness(trig_data, LED_OFF);
|
||||
|
||||
trig_data->prev_traffic = traffic;
|
||||
}
|
||||
|
||||
trig_data->prev_link = link;
|
||||
}
|
||||
|
||||
static void
|
||||
swconfig_trig_update_leds(struct switch_led_trigger *sw_trig)
|
||||
{
|
||||
struct list_head *entry;
|
||||
struct led_trigger *trigger;
|
||||
|
||||
trigger = &sw_trig->trig;
|
||||
spin_lock(&trigger->leddev_list_lock);
|
||||
list_for_each(entry, &trigger->led_cdevs) {
|
||||
struct led_classdev *led_cdev;
|
||||
|
||||
led_cdev = list_entry(entry, struct led_classdev, trig_list);
|
||||
swconfig_trig_led_event(sw_trig, led_cdev);
|
||||
}
|
||||
spin_unlock(&trigger->leddev_list_lock);
|
||||
}
|
||||
|
||||
static void
|
||||
swconfig_led_work_func(struct work_struct *work)
|
||||
{
|
||||
struct switch_led_trigger *sw_trig;
|
||||
struct switch_dev *swdev;
|
||||
u32 port_mask;
|
||||
u32 link;
|
||||
int i;
|
||||
|
||||
sw_trig = container_of(work, struct switch_led_trigger,
|
||||
sw_led_work.work);
|
||||
|
||||
port_mask = sw_trig->port_mask;
|
||||
swdev = sw_trig->swdev;
|
||||
|
||||
link = 0;
|
||||
for (i = 0; i < SWCONFIG_LED_NUM_PORTS; i++) {
|
||||
u32 port_bit;
|
||||
|
||||
sw_trig->link_speed[i] = 0;
|
||||
|
||||
port_bit = BIT(i);
|
||||
if ((port_mask & port_bit) == 0)
|
||||
continue;
|
||||
|
||||
if (swdev->ops->get_port_link) {
|
||||
struct switch_port_link port_link;
|
||||
|
||||
memset(&port_link, '\0', sizeof(port_link));
|
||||
swdev->ops->get_port_link(swdev, i, &port_link);
|
||||
|
||||
if (port_link.link) {
|
||||
link |= port_bit;
|
||||
switch (port_link.speed) {
|
||||
case SWITCH_PORT_SPEED_UNKNOWN:
|
||||
sw_trig->link_speed[i] =
|
||||
SWCONFIG_LED_PORT_SPEED_NA;
|
||||
break;
|
||||
case SWITCH_PORT_SPEED_10:
|
||||
sw_trig->link_speed[i] =
|
||||
SWCONFIG_LED_PORT_SPEED_10;
|
||||
break;
|
||||
case SWITCH_PORT_SPEED_100:
|
||||
sw_trig->link_speed[i] =
|
||||
SWCONFIG_LED_PORT_SPEED_100;
|
||||
break;
|
||||
case SWITCH_PORT_SPEED_1000:
|
||||
sw_trig->link_speed[i] =
|
||||
SWCONFIG_LED_PORT_SPEED_1000;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (swdev->ops->get_port_stats) {
|
||||
struct switch_port_stats port_stats;
|
||||
|
||||
memset(&port_stats, '\0', sizeof(port_stats));
|
||||
swdev->ops->get_port_stats(swdev, i, &port_stats);
|
||||
sw_trig->port_tx_traffic[i] = port_stats.tx_bytes;
|
||||
sw_trig->port_rx_traffic[i] = port_stats.rx_bytes;
|
||||
}
|
||||
}
|
||||
|
||||
sw_trig->port_link = link;
|
||||
|
||||
swconfig_trig_update_leds(sw_trig);
|
||||
|
||||
schedule_delayed_work(&sw_trig->sw_led_work,
|
||||
SWCONFIG_LED_TIMER_INTERVAL);
|
||||
}
|
||||
|
||||
static int
|
||||
swconfig_create_led_trigger(struct switch_dev *swdev)
|
||||
{
|
||||
struct switch_led_trigger *sw_trig;
|
||||
int err;
|
||||
|
||||
if (!swdev->ops->get_port_link)
|
||||
return 0;
|
||||
|
||||
sw_trig = kzalloc(sizeof(struct switch_led_trigger), GFP_KERNEL);
|
||||
if (!sw_trig)
|
||||
return -ENOMEM;
|
||||
|
||||
sw_trig->swdev = swdev;
|
||||
sw_trig->trig.name = swdev->devname;
|
||||
sw_trig->trig.activate = swconfig_trig_activate;
|
||||
sw_trig->trig.deactivate = swconfig_trig_deactivate;
|
||||
|
||||
INIT_DELAYED_WORK(&sw_trig->sw_led_work, swconfig_led_work_func);
|
||||
|
||||
err = led_trigger_register(&sw_trig->trig);
|
||||
if (err)
|
||||
goto err_free;
|
||||
|
||||
swdev->led_trigger = sw_trig;
|
||||
|
||||
return 0;
|
||||
|
||||
err_free:
|
||||
kfree(sw_trig);
|
||||
return err;
|
||||
}
|
||||
|
||||
static void
|
||||
swconfig_destroy_led_trigger(struct switch_dev *swdev)
|
||||
{
|
||||
struct switch_led_trigger *sw_trig;
|
||||
|
||||
sw_trig = swdev->led_trigger;
|
||||
if (sw_trig) {
|
||||
cancel_delayed_work_sync(&sw_trig->sw_led_work);
|
||||
led_trigger_unregister(&sw_trig->trig);
|
||||
kfree(sw_trig);
|
||||
}
|
||||
}
|
||||
|
||||
#else /* SWCONFIG_LEDS */
|
||||
static inline int
|
||||
swconfig_create_led_trigger(struct switch_dev *swdev) { return 0; }
|
||||
|
||||
static inline void
|
||||
swconfig_destroy_led_trigger(struct switch_dev *swdev) { }
|
||||
#endif /* CONFIG_SWCONFIG_LEDS */
|
Loading…
Add table
Add a link
Reference in a new issue