2019-05-27 08:55:01 +02:00
// SPDX-License-Identifier: GPL-2.0-or-later
2016-09-02 14:45:33 -04:00
/*
2017-06-19 10:55:45 -04:00
* Marvell 88E6 xxx Switch Global 2 Registers support
2016-09-02 14:45:33 -04:00
*
* Copyright ( c ) 2008 Marvell Semiconductor
*
2017-03-28 15:10:36 -04:00
* Copyright ( c ) 2016 - 2017 Savoir - faire Linux Inc .
* Vivien Didelot < vivien . didelot @ savoirfairelinux . com >
2016-09-02 14:45:33 -04:00
*/
2017-06-19 10:55:37 -04:00
# include <linux/bitfield.h>
2017-03-29 17:17:31 +02:00
# include <linux/interrupt.h>
2016-10-16 19:56:49 +02:00
# include <linux/irqdomain.h>
2017-06-02 17:06:15 -04:00
# include "chip.h"
2017-06-15 12:13:59 -04:00
# include "global1.h" /* for MV88E6XXX_G1_STS_IRQ_DEVICE */
2016-09-02 14:45:33 -04:00
# include "global2.h"
2018-02-14 01:07:43 +01:00
int mv88e6xxx_g2_read ( struct mv88e6xxx_chip * chip , int reg , u16 * val )
2016-09-29 12:21:54 -04:00
{
2017-07-17 13:03:44 -04:00
return mv88e6xxx_read ( chip , chip - > info - > global2_addr , reg , val ) ;
2016-09-29 12:21:54 -04:00
}
2018-02-14 01:07:43 +01:00
int mv88e6xxx_g2_write ( struct mv88e6xxx_chip * chip , int reg , u16 val )
2016-09-29 12:21:54 -04:00
{
2017-07-17 13:03:44 -04:00
return mv88e6xxx_write ( chip , chip - > info - > global2_addr , reg , val ) ;
2016-09-29 12:21:54 -04:00
}
2019-08-09 18:47:55 -04:00
int mv88e6xxx_g2_wait_bit ( struct mv88e6xxx_chip * chip , int reg , int
bit , int val )
{
return mv88e6xxx_wait_bit ( chip , chip - > info - > global2_addr , reg ,
bit , val ) ;
}
2017-07-17 13:03:40 -04:00
/* Offset 0x00: Interrupt Source Register */
static int mv88e6xxx_g2_int_source ( struct mv88e6xxx_chip * chip , u16 * src )
{
/* Read (and clear most of) the Interrupt Source bits */
return mv88e6xxx_g2_read ( chip , MV88E6XXX_G2_INT_SRC , src ) ;
}
/* Offset 0x01: Interrupt Mask Register */
static int mv88e6xxx_g2_int_mask ( struct mv88e6xxx_chip * chip , u16 mask )
{
return mv88e6xxx_g2_write ( chip , MV88E6XXX_G2_INT_MASK , mask ) ;
}
2016-12-03 04:45:16 +01:00
/* Offset 0x02: Management Enable 2x */
2017-07-17 13:03:41 -04:00
static int mv88e6xxx_g2_mgmt_enable_2x ( struct mv88e6xxx_chip * chip , u16 en2x )
{
return mv88e6xxx_g2_write ( chip , MV88E6XXX_G2_MGMT_EN_2X , en2x ) ;
}
2016-12-03 04:45:16 +01:00
/* Offset 0x03: Management Enable 0x */
2017-07-17 13:03:41 -04:00
static int mv88e6xxx_g2_mgmt_enable_0x ( struct mv88e6xxx_chip * chip , u16 en0x )
{
return mv88e6xxx_g2_write ( chip , MV88E6XXX_G2_MGMT_EN_0X , en0x ) ;
}
/* Offset 0x05: Switch Management Register */
static int mv88e6xxx_g2_switch_mgmt_rsvd2cpu ( struct mv88e6xxx_chip * chip ,
bool enable )
{
u16 val ;
int err ;
err = mv88e6xxx_g2_read ( chip , MV88E6XXX_G2_SWITCH_MGMT , & val ) ;
if ( err )
return err ;
if ( enable )
val | = MV88E6XXX_G2_SWITCH_MGMT_RSVD2CPU ;
else
val & = ~ MV88E6XXX_G2_SWITCH_MGMT_RSVD2CPU ;
return mv88e6xxx_g2_write ( chip , MV88E6XXX_G2_SWITCH_MGMT , val ) ;
}
int mv88e6185_g2_mgmt_rsvd2cpu ( struct mv88e6xxx_chip * chip )
2016-12-03 04:45:16 +01:00
{
int err ;
/* Consider the frames with reserved multicast destination
2017-07-17 13:03:41 -04:00
* addresses matching 01 : 80 : c2 : 00 : 00 : 0 x as MGMT .
2016-12-03 04:45:16 +01:00
*/
2017-07-17 13:03:41 -04:00
err = mv88e6xxx_g2_mgmt_enable_0x ( chip , 0xffff ) ;
if ( err )
return err ;
return mv88e6xxx_g2_switch_mgmt_rsvd2cpu ( chip , true ) ;
}
int mv88e6352_g2_mgmt_rsvd2cpu ( struct mv88e6xxx_chip * chip )
{
int err ;
2016-12-03 04:45:16 +01:00
/* Consider the frames with reserved multicast destination
2017-07-17 13:03:41 -04:00
* addresses matching 01 : 80 : c2 : 00 : 00 : 2 x as MGMT .
2016-12-03 04:45:16 +01:00
*/
2017-07-17 13:03:41 -04:00
err = mv88e6xxx_g2_mgmt_enable_2x ( chip , 0xffff ) ;
if ( err )
return err ;
2016-12-03 04:45:16 +01:00
2017-07-17 13:03:41 -04:00
return mv88e6185_g2_mgmt_rsvd2cpu ( chip ) ;
2016-12-03 04:45:16 +01:00
}
2016-09-02 14:45:33 -04:00
/* Offset 0x06: Device Mapping Table register */
2018-04-26 21:56:45 -04:00
int mv88e6xxx_g2_device_mapping_write ( struct mv88e6xxx_chip * chip , int target ,
int port )
2016-09-02 14:45:33 -04:00
{
2018-04-26 21:56:45 -04:00
u16 val = ( target < < 8 ) | ( port & 0x1f ) ;
/* Modern chips use 5 bits to define a device mapping port,
* but bit 4 is reserved on older chips , so it is safe to use .
*/
2016-09-02 14:45:33 -04:00
2019-08-09 18:47:57 -04:00
return mv88e6xxx_g2_write ( chip , MV88E6XXX_G2_DEVICE_MAPPING ,
MV88E6XXX_G2_DEVICE_MAPPING_UPDATE | val ) ;
2016-09-02 14:45:33 -04:00
}
/* Offset 0x07: Trunk Mask Table register */
static int mv88e6xxx_g2_trunk_mask_write ( struct mv88e6xxx_chip * chip , int num ,
2017-06-19 10:55:38 -04:00
bool hash , u16 mask )
2016-09-02 14:45:33 -04:00
{
2017-06-19 10:55:38 -04:00
u16 val = ( num < < 12 ) | ( mask & mv88e6xxx_port_mask ( chip ) ) ;
2016-09-02 14:45:33 -04:00
2017-06-19 10:55:38 -04:00
if ( hash )
val | = MV88E6XXX_G2_TRUNK_MASK_HASH ;
2016-09-02 14:45:33 -04:00
2019-08-09 18:47:57 -04:00
return mv88e6xxx_g2_write ( chip , MV88E6XXX_G2_TRUNK_MASK ,
MV88E6XXX_G2_TRUNK_MASK_UPDATE | val ) ;
2016-09-02 14:45:33 -04:00
}
/* Offset 0x08: Trunk Mapping Table register */
static int mv88e6xxx_g2_trunk_mapping_write ( struct mv88e6xxx_chip * chip , int id ,
u16 map )
{
2016-09-29 12:21:57 -04:00
const u16 port_mask = BIT ( mv88e6xxx_num_ports ( chip ) ) - 1 ;
2016-09-02 14:45:33 -04:00
u16 val = ( id < < 11 ) | ( map & port_mask ) ;
2019-08-09 18:47:57 -04:00
return mv88e6xxx_g2_write ( chip , MV88E6XXX_G2_TRUNK_MAPPING ,
MV88E6XXX_G2_TRUNK_MAPPING_UPDATE | val ) ;
2016-09-02 14:45:33 -04:00
}
2018-04-26 21:56:44 -04:00
int mv88e6xxx_g2_trunk_clear ( struct mv88e6xxx_chip * chip )
2016-09-02 14:45:33 -04:00
{
2016-09-29 12:21:57 -04:00
const u16 port_mask = BIT ( mv88e6xxx_num_ports ( chip ) ) - 1 ;
2016-09-02 14:45:33 -04:00
int i , err ;
/* Clear all eight possible Trunk Mask vectors */
for ( i = 0 ; i < 8 ; + + i ) {
err = mv88e6xxx_g2_trunk_mask_write ( chip , i , false , port_mask ) ;
if ( err )
return err ;
}
/* Clear all sixteen possible Trunk ID routing vectors */
for ( i = 0 ; i < 16 ; + + i ) {
err = mv88e6xxx_g2_trunk_mapping_write ( chip , i , 0 ) ;
if ( err )
return err ;
}
return 0 ;
}
/* Offset 0x09: Ingress Rate Command register
* Offset 0x0A : Ingress Rate Data register
*/
2017-06-19 10:55:36 -04:00
static int mv88e6xxx_g2_irl_wait ( struct mv88e6xxx_chip * chip )
2016-09-02 14:45:33 -04:00
{
2019-08-09 18:47:55 -04:00
int bit = __bf_shf ( MV88E6XXX_G2_IRL_CMD_BUSY ) ;
return mv88e6xxx_g2_wait_bit ( chip , MV88E6XXX_G2_IRL_CMD , bit , 0 ) ;
2017-06-19 10:55:36 -04:00
}
2016-09-02 14:45:33 -04:00
2017-06-19 10:55:36 -04:00
static int mv88e6xxx_g2_irl_op ( struct mv88e6xxx_chip * chip , u16 op , int port ,
int res , int reg )
{
int err ;
2016-09-02 14:45:33 -04:00
2017-06-19 10:55:36 -04:00
err = mv88e6xxx_g2_write ( chip , MV88E6XXX_G2_IRL_CMD ,
MV88E6XXX_G2_IRL_CMD_BUSY | op | ( port < < 8 ) |
( res < < 5 ) | reg ) ;
if ( err )
return err ;
return mv88e6xxx_g2_irl_wait ( chip ) ;
}
int mv88e6352_g2_irl_init_all ( struct mv88e6xxx_chip * chip , int port )
{
return mv88e6xxx_g2_irl_op ( chip , MV88E6352_G2_IRL_CMD_OP_INIT_ALL , port ,
0 , 0 ) ;
}
int mv88e6390_g2_irl_init_all ( struct mv88e6xxx_chip * chip , int port )
{
return mv88e6xxx_g2_irl_op ( chip , MV88E6390_G2_IRL_CMD_OP_INIT_ALL , port ,
0 , 0 ) ;
2016-09-02 14:45:33 -04:00
}
2017-03-30 17:37:09 -04:00
/* Offset 0x0B: Cross-chip Port VLAN (Addr) Register
* Offset 0x0C : Cross - chip Port VLAN Data Register
*/
static int mv88e6xxx_g2_pvt_op_wait ( struct mv88e6xxx_chip * chip )
{
2019-08-09 18:47:55 -04:00
int bit = __bf_shf ( MV88E6XXX_G2_PVT_ADDR_BUSY ) ;
return mv88e6xxx_g2_wait_bit ( chip , MV88E6XXX_G2_PVT_ADDR , bit , 0 ) ;
2017-03-30 17:37:09 -04:00
}
static int mv88e6xxx_g2_pvt_op ( struct mv88e6xxx_chip * chip , int src_dev ,
int src_port , u16 op )
{
int err ;
2017-06-19 10:55:41 -04:00
/* 9-bit Cross-chip PVT pointer: with MV88E6XXX_G2_MISC_5_BIT_PORT
* cleared , source device is 5 - bit , source port is 4 - bit .
2017-03-30 17:37:09 -04:00
*/
2017-06-19 10:55:41 -04:00
op | = MV88E6XXX_G2_PVT_ADDR_BUSY ;
2017-03-30 17:37:09 -04:00
op | = ( src_dev & 0x1f ) < < 4 ;
op | = ( src_port & 0xf ) ;
2017-06-19 10:55:41 -04:00
err = mv88e6xxx_g2_write ( chip , MV88E6XXX_G2_PVT_ADDR , op ) ;
2017-03-30 17:37:09 -04:00
if ( err )
return err ;
return mv88e6xxx_g2_pvt_op_wait ( chip ) ;
}
int mv88e6xxx_g2_pvt_write ( struct mv88e6xxx_chip * chip , int src_dev ,
int src_port , u16 data )
{
int err ;
err = mv88e6xxx_g2_pvt_op_wait ( chip ) ;
if ( err )
return err ;
2017-06-19 10:55:41 -04:00
err = mv88e6xxx_g2_write ( chip , MV88E6XXX_G2_PVT_DATA , data ) ;
2017-03-30 17:37:09 -04:00
if ( err )
return err ;
return mv88e6xxx_g2_pvt_op ( chip , src_dev , src_port ,
2017-06-19 10:55:41 -04:00
MV88E6XXX_G2_PVT_ADDR_OP_WRITE_PVLAN ) ;
2017-03-30 17:37:09 -04:00
}
2016-09-02 14:45:33 -04:00
/* Offset 0x0D: Switch MAC/WoL/WoF register */
static int mv88e6xxx_g2_switch_mac_write ( struct mv88e6xxx_chip * chip ,
unsigned int pointer , u8 data )
{
u16 val = ( pointer < < 8 ) | data ;
2019-08-09 18:47:57 -04:00
return mv88e6xxx_g2_write ( chip , MV88E6XXX_G2_SWITCH_MAC ,
MV88E6XXX_G2_SWITCH_MAC_UPDATE | val ) ;
2016-09-02 14:45:33 -04:00
}
int mv88e6xxx_g2_set_switch_mac ( struct mv88e6xxx_chip * chip , u8 * addr )
{
int i , err ;
for ( i = 0 ; i < 6 ; i + + ) {
err = mv88e6xxx_g2_switch_mac_write ( chip , i , addr [ i ] ) ;
if ( err )
break ;
}
return err ;
}
2019-11-05 01:12:59 +01:00
/* Offset 0x0E: ATU Statistics */
int mv88e6xxx_g2_atu_stats_set ( struct mv88e6xxx_chip * chip , u16 kind , u16 bin )
{
return mv88e6xxx_g2_write ( chip , MV88E6XXX_G2_ATU_STATS ,
kind | bin ) ;
}
2019-11-05 01:13:00 +01:00
int mv88e6xxx_g2_atu_stats_get ( struct mv88e6xxx_chip * chip , u16 * stats )
2019-11-05 01:12:59 +01:00
{
2019-11-05 01:13:00 +01:00
return mv88e6xxx_g2_read ( chip , MV88E6XXX_G2_ATU_STATS , stats ) ;
2019-11-05 01:12:59 +01:00
}
2016-09-02 14:45:33 -04:00
/* Offset 0x0F: Priority Override Table */
static int mv88e6xxx_g2_pot_write ( struct mv88e6xxx_chip * chip , int pointer ,
u8 data )
{
u16 val = ( pointer < < 8 ) | ( data & 0x7 ) ;
2019-08-09 18:47:57 -04:00
return mv88e6xxx_g2_write ( chip , MV88E6XXX_G2_PRIO_OVERRIDE ,
MV88E6XXX_G2_PRIO_OVERRIDE_UPDATE | val ) ;
2016-09-02 14:45:33 -04:00
}
2017-07-17 13:03:43 -04:00
int mv88e6xxx_g2_pot_clear ( struct mv88e6xxx_chip * chip )
2016-09-02 14:45:33 -04:00
{
int i , err ;
/* Clear all sixteen possible Priority Override entries */
for ( i = 0 ; i < 16 ; i + + ) {
err = mv88e6xxx_g2_pot_write ( chip , i , 0 ) ;
if ( err )
break ;
}
return err ;
}
/* Offset 0x14: EEPROM Command
2017-01-12 18:07:16 -05:00
* Offset 0x15 : EEPROM Data ( for 16 - bit data access )
* Offset 0x15 : EEPROM Addr ( for 8 - bit data access )
2016-09-02 14:45:33 -04:00
*/
static int mv88e6xxx_g2_eeprom_wait ( struct mv88e6xxx_chip * chip )
{
2019-08-09 18:47:55 -04:00
int bit = __bf_shf ( MV88E6XXX_G2_EEPROM_CMD_BUSY ) ;
int err ;
err = mv88e6xxx_g2_wait_bit ( chip , MV88E6XXX_G2_EEPROM_CMD , bit , 0 ) ;
if ( err )
return err ;
bit = __bf_shf ( MV88E6XXX_G2_EEPROM_CMD_RUNNING ) ;
return mv88e6xxx_g2_wait_bit ( chip , MV88E6XXX_G2_EEPROM_CMD , bit , 0 ) ;
2016-09-02 14:45:33 -04:00
}
static int mv88e6xxx_g2_eeprom_cmd ( struct mv88e6xxx_chip * chip , u16 cmd )
{
int err ;
2017-06-19 10:55:42 -04:00
err = mv88e6xxx_g2_write ( chip , MV88E6XXX_G2_EEPROM_CMD ,
MV88E6XXX_G2_EEPROM_CMD_BUSY | cmd ) ;
2016-09-02 14:45:33 -04:00
if ( err )
return err ;
return mv88e6xxx_g2_eeprom_wait ( chip ) ;
}
2017-01-12 18:07:16 -05:00
static int mv88e6xxx_g2_eeprom_read8 ( struct mv88e6xxx_chip * chip ,
u16 addr , u8 * data )
{
2017-06-19 10:55:42 -04:00
u16 cmd = MV88E6XXX_G2_EEPROM_CMD_OP_READ ;
2017-01-12 18:07:16 -05:00
int err ;
err = mv88e6xxx_g2_eeprom_wait ( chip ) ;
if ( err )
return err ;
2017-06-19 10:55:42 -04:00
err = mv88e6xxx_g2_write ( chip , MV88E6390_G2_EEPROM_ADDR , addr ) ;
2017-01-12 18:07:16 -05:00
if ( err )
return err ;
err = mv88e6xxx_g2_eeprom_cmd ( chip , cmd ) ;
if ( err )
return err ;
2017-06-19 10:55:42 -04:00
err = mv88e6xxx_g2_read ( chip , MV88E6XXX_G2_EEPROM_CMD , & cmd ) ;
2017-01-12 18:07:16 -05:00
if ( err )
return err ;
* data = cmd & 0xff ;
return 0 ;
}
static int mv88e6xxx_g2_eeprom_write8 ( struct mv88e6xxx_chip * chip ,
u16 addr , u8 data )
{
2017-06-19 10:55:42 -04:00
u16 cmd = MV88E6XXX_G2_EEPROM_CMD_OP_WRITE |
MV88E6XXX_G2_EEPROM_CMD_WRITE_EN ;
2017-01-12 18:07:16 -05:00
int err ;
err = mv88e6xxx_g2_eeprom_wait ( chip ) ;
if ( err )
return err ;
2017-06-19 10:55:42 -04:00
err = mv88e6xxx_g2_write ( chip , MV88E6390_G2_EEPROM_ADDR , addr ) ;
2017-01-12 18:07:16 -05:00
if ( err )
return err ;
return mv88e6xxx_g2_eeprom_cmd ( chip , cmd | data ) ;
}
2016-09-02 14:45:33 -04:00
static int mv88e6xxx_g2_eeprom_read16 ( struct mv88e6xxx_chip * chip ,
u8 addr , u16 * data )
{
2017-06-19 10:55:42 -04:00
u16 cmd = MV88E6XXX_G2_EEPROM_CMD_OP_READ | addr ;
2016-09-02 14:45:33 -04:00
int err ;
err = mv88e6xxx_g2_eeprom_wait ( chip ) ;
if ( err )
return err ;
err = mv88e6xxx_g2_eeprom_cmd ( chip , cmd ) ;
if ( err )
return err ;
2017-06-19 10:55:42 -04:00
return mv88e6xxx_g2_read ( chip , MV88E6352_G2_EEPROM_DATA , data ) ;
2016-09-02 14:45:33 -04:00
}
static int mv88e6xxx_g2_eeprom_write16 ( struct mv88e6xxx_chip * chip ,
u8 addr , u16 data )
{
2017-06-19 10:55:42 -04:00
u16 cmd = MV88E6XXX_G2_EEPROM_CMD_OP_WRITE | addr ;
2016-09-02 14:45:33 -04:00
int err ;
err = mv88e6xxx_g2_eeprom_wait ( chip ) ;
if ( err )
return err ;
2017-06-19 10:55:42 -04:00
err = mv88e6xxx_g2_write ( chip , MV88E6352_G2_EEPROM_DATA , data ) ;
2016-09-02 14:45:33 -04:00
if ( err )
return err ;
return mv88e6xxx_g2_eeprom_cmd ( chip , cmd ) ;
}
2017-01-12 18:07:16 -05:00
int mv88e6xxx_g2_get_eeprom8 ( struct mv88e6xxx_chip * chip ,
struct ethtool_eeprom * eeprom , u8 * data )
{
unsigned int offset = eeprom - > offset ;
unsigned int len = eeprom - > len ;
int err ;
eeprom - > len = 0 ;
while ( len ) {
err = mv88e6xxx_g2_eeprom_read8 ( chip , offset , data ) ;
if ( err )
return err ;
eeprom - > len + + ;
offset + + ;
data + + ;
len - - ;
}
return 0 ;
}
int mv88e6xxx_g2_set_eeprom8 ( struct mv88e6xxx_chip * chip ,
struct ethtool_eeprom * eeprom , u8 * data )
{
unsigned int offset = eeprom - > offset ;
unsigned int len = eeprom - > len ;
int err ;
eeprom - > len = 0 ;
while ( len ) {
err = mv88e6xxx_g2_eeprom_write8 ( chip , offset , * data ) ;
if ( err )
return err ;
eeprom - > len + + ;
offset + + ;
data + + ;
len - - ;
}
return 0 ;
}
2016-09-02 14:45:33 -04:00
int mv88e6xxx_g2_get_eeprom16 ( struct mv88e6xxx_chip * chip ,
struct ethtool_eeprom * eeprom , u8 * data )
{
unsigned int offset = eeprom - > offset ;
unsigned int len = eeprom - > len ;
u16 val ;
int err ;
eeprom - > len = 0 ;
if ( offset & 1 ) {
err = mv88e6xxx_g2_eeprom_read16 ( chip , offset > > 1 , & val ) ;
if ( err )
return err ;
* data + + = ( val > > 8 ) & 0xff ;
offset + + ;
len - - ;
eeprom - > len + + ;
}
while ( len > = 2 ) {
err = mv88e6xxx_g2_eeprom_read16 ( chip , offset > > 1 , & val ) ;
if ( err )
return err ;
* data + + = val & 0xff ;
* data + + = ( val > > 8 ) & 0xff ;
offset + = 2 ;
len - = 2 ;
eeprom - > len + = 2 ;
}
if ( len ) {
err = mv88e6xxx_g2_eeprom_read16 ( chip , offset > > 1 , & val ) ;
if ( err )
return err ;
* data + + = val & 0xff ;
offset + + ;
len - - ;
eeprom - > len + + ;
}
return 0 ;
}
int mv88e6xxx_g2_set_eeprom16 ( struct mv88e6xxx_chip * chip ,
struct ethtool_eeprom * eeprom , u8 * data )
{
unsigned int offset = eeprom - > offset ;
unsigned int len = eeprom - > len ;
u16 val ;
int err ;
/* Ensure the RO WriteEn bit is set */
2017-06-19 10:55:42 -04:00
err = mv88e6xxx_g2_read ( chip , MV88E6XXX_G2_EEPROM_CMD , & val ) ;
2016-09-02 14:45:33 -04:00
if ( err )
return err ;
2017-06-19 10:55:42 -04:00
if ( ! ( val & MV88E6XXX_G2_EEPROM_CMD_WRITE_EN ) )
2016-09-02 14:45:33 -04:00
return - EROFS ;
eeprom - > len = 0 ;
if ( offset & 1 ) {
err = mv88e6xxx_g2_eeprom_read16 ( chip , offset > > 1 , & val ) ;
if ( err )
return err ;
val = ( * data + + < < 8 ) | ( val & 0xff ) ;
err = mv88e6xxx_g2_eeprom_write16 ( chip , offset > > 1 , val ) ;
if ( err )
return err ;
offset + + ;
len - - ;
eeprom - > len + + ;
}
while ( len > = 2 ) {
val = * data + + ;
val | = * data + + < < 8 ;
err = mv88e6xxx_g2_eeprom_write16 ( chip , offset > > 1 , val ) ;
if ( err )
return err ;
offset + = 2 ;
len - = 2 ;
eeprom - > len + = 2 ;
}
if ( len ) {
err = mv88e6xxx_g2_eeprom_read16 ( chip , offset > > 1 , & val ) ;
if ( err )
return err ;
val = ( val & 0xff00 ) | * data + + ;
err = mv88e6xxx_g2_eeprom_write16 ( chip , offset > > 1 , val ) ;
if ( err )
return err ;
offset + + ;
len - - ;
eeprom - > len + + ;
}
return 0 ;
}
/* Offset 0x18: SMI PHY Command Register
* Offset 0x19 : SMI PHY Data Register
*/
static int mv88e6xxx_g2_smi_phy_wait ( struct mv88e6xxx_chip * chip )
{
2019-08-09 18:47:55 -04:00
int bit = __bf_shf ( MV88E6XXX_G2_SMI_PHY_CMD_BUSY ) ;
return mv88e6xxx_g2_wait_bit ( chip , MV88E6XXX_G2_SMI_PHY_CMD , bit , 0 ) ;
2016-09-02 14:45:33 -04:00
}
static int mv88e6xxx_g2_smi_phy_cmd ( struct mv88e6xxx_chip * chip , u16 cmd )
{
int err ;
2017-06-19 10:55:37 -04:00
err = mv88e6xxx_g2_write ( chip , MV88E6XXX_G2_SMI_PHY_CMD ,
MV88E6XXX_G2_SMI_PHY_CMD_BUSY | cmd ) ;
2016-09-02 14:45:33 -04:00
if ( err )
return err ;
return mv88e6xxx_g2_smi_phy_wait ( chip ) ;
}
2017-06-19 10:55:37 -04:00
static int mv88e6xxx_g2_smi_phy_access ( struct mv88e6xxx_chip * chip ,
bool external , bool c45 , u16 op , int dev ,
int reg )
2017-02-04 20:12:24 +01:00
{
2017-06-19 10:55:37 -04:00
u16 cmd = op ;
2017-02-04 20:12:24 +01:00
if ( external )
2017-06-19 10:55:37 -04:00
cmd | = MV88E6390_G2_SMI_PHY_CMD_FUNC_EXTERNAL ;
else
cmd | = MV88E6390_G2_SMI_PHY_CMD_FUNC_INTERNAL ; /* empty mask */
2017-02-04 20:12:24 +01:00
2017-06-19 10:55:37 -04:00
if ( c45 )
cmd | = MV88E6XXX_G2_SMI_PHY_CMD_MODE_45 ; /* empty mask */
else
cmd | = MV88E6XXX_G2_SMI_PHY_CMD_MODE_22 ;
2017-02-04 20:12:24 +01:00
2017-06-19 10:55:37 -04:00
dev < < = __bf_shf ( MV88E6XXX_G2_SMI_PHY_CMD_DEV_ADDR_MASK ) ;
cmd | = dev & MV88E6XXX_G2_SMI_PHY_CMD_DEV_ADDR_MASK ;
cmd | = reg & MV88E6XXX_G2_SMI_PHY_CMD_REG_ADDR_MASK ;
2017-02-04 20:12:24 +01:00
return mv88e6xxx_g2_smi_phy_cmd ( chip , cmd ) ;
}
2017-06-19 10:55:37 -04:00
static int mv88e6xxx_g2_smi_phy_access_c22 ( struct mv88e6xxx_chip * chip ,
bool external , u16 op , int dev ,
int reg )
2017-02-04 20:12:24 +01:00
{
2017-06-19 10:55:37 -04:00
return mv88e6xxx_g2_smi_phy_access ( chip , external , false , op , dev , reg ) ;
}
/* IEEE 802.3 Clause 22 Read Data Register */
static int mv88e6xxx_g2_smi_phy_read_data_c22 ( struct mv88e6xxx_chip * chip ,
bool external , int dev , int reg ,
u16 * data )
{
u16 op = MV88E6XXX_G2_SMI_PHY_CMD_OP_22_READ_DATA ;
2017-02-04 20:12:24 +01:00
int err ;
2017-06-19 10:55:37 -04:00
err = mv88e6xxx_g2_smi_phy_wait ( chip ) ;
2017-02-04 20:12:24 +01:00
if ( err )
return err ;
2017-06-19 10:55:37 -04:00
err = mv88e6xxx_g2_smi_phy_access_c22 ( chip , external , op , dev , reg ) ;
if ( err )
return err ;
2017-02-04 20:12:24 +01:00
2017-06-19 10:55:37 -04:00
return mv88e6xxx_g2_read ( chip , MV88E6XXX_G2_SMI_PHY_DATA , data ) ;
}
2017-02-04 20:12:24 +01:00
2017-06-19 10:55:37 -04:00
/* IEEE 802.3 Clause 22 Write Data Register */
static int mv88e6xxx_g2_smi_phy_write_data_c22 ( struct mv88e6xxx_chip * chip ,
bool external , int dev , int reg ,
u16 data )
{
u16 op = MV88E6XXX_G2_SMI_PHY_CMD_OP_22_WRITE_DATA ;
int err ;
err = mv88e6xxx_g2_smi_phy_wait ( chip ) ;
2017-02-04 20:12:24 +01:00
if ( err )
return err ;
2017-06-19 10:55:37 -04:00
err = mv88e6xxx_g2_write ( chip , MV88E6XXX_G2_SMI_PHY_DATA , data ) ;
2017-02-04 20:12:24 +01:00
if ( err )
return err ;
2017-06-19 10:55:37 -04:00
return mv88e6xxx_g2_smi_phy_access_c22 ( chip , external , op , dev , reg ) ;
}
2017-02-04 20:12:24 +01:00
2017-06-19 10:55:37 -04:00
static int mv88e6xxx_g2_smi_phy_access_c45 ( struct mv88e6xxx_chip * chip ,
bool external , u16 op , int port ,
int dev )
{
return mv88e6xxx_g2_smi_phy_access ( chip , external , true , op , port , dev ) ;
2017-02-04 20:12:24 +01:00
}
2017-06-19 10:55:37 -04:00
/* IEEE 802.3 Clause 45 Write Address Register */
static int mv88e6xxx_g2_smi_phy_write_addr_c45 ( struct mv88e6xxx_chip * chip ,
bool external , int port , int dev ,
int addr )
2017-02-04 20:12:24 +01:00
{
2017-06-19 10:55:37 -04:00
u16 op = MV88E6XXX_G2_SMI_PHY_CMD_OP_45_WRITE_ADDR ;
2017-02-04 20:12:24 +01:00
int err ;
err = mv88e6xxx_g2_smi_phy_wait ( chip ) ;
if ( err )
return err ;
2017-06-19 10:55:37 -04:00
err = mv88e6xxx_g2_write ( chip , MV88E6XXX_G2_SMI_PHY_DATA , addr ) ;
2017-02-04 20:12:24 +01:00
if ( err )
return err ;
2017-06-19 10:55:37 -04:00
return mv88e6xxx_g2_smi_phy_access_c45 ( chip , external , op , port , dev ) ;
2017-02-04 20:12:24 +01:00
}
2017-06-19 10:55:37 -04:00
/* IEEE 802.3 Clause 45 Read Data Register */
static int mv88e6xxx_g2_smi_phy_read_data_c45 ( struct mv88e6xxx_chip * chip ,
bool external , int port , int dev ,
u16 * data )
2016-09-02 14:45:33 -04:00
{
2017-06-19 10:55:37 -04:00
u16 op = MV88E6XXX_G2_SMI_PHY_CMD_OP_45_READ_DATA ;
int err ;
2017-02-04 20:12:24 +01:00
2017-06-19 10:55:37 -04:00
err = mv88e6xxx_g2_smi_phy_access_c45 ( chip , external , op , port , dev ) ;
if ( err )
return err ;
return mv88e6xxx_g2_read ( chip , MV88E6XXX_G2_SMI_PHY_DATA , data ) ;
2017-02-04 20:12:24 +01:00
}
2017-06-19 10:55:37 -04:00
static int mv88e6xxx_g2_smi_phy_read_c45 ( struct mv88e6xxx_chip * chip ,
bool external , int port , int reg ,
u16 * data )
2017-02-04 20:12:24 +01:00
{
2017-06-19 10:55:37 -04:00
int dev = ( reg > > 16 ) & 0x1f ;
int addr = reg & 0xffff ;
2016-09-02 14:45:33 -04:00
int err ;
2017-06-19 10:55:37 -04:00
err = mv88e6xxx_g2_smi_phy_write_addr_c45 ( chip , external , port , dev ,
addr ) ;
2017-02-04 20:12:24 +01:00
if ( err )
return err ;
2017-06-19 10:55:37 -04:00
return mv88e6xxx_g2_smi_phy_read_data_c45 ( chip , external , port , dev ,
data ) ;
}
2017-01-24 14:53:51 +01:00
2017-06-19 10:55:37 -04:00
/* IEEE 802.3 Clause 45 Write Data Register */
static int mv88e6xxx_g2_smi_phy_write_data_c45 ( struct mv88e6xxx_chip * chip ,
bool external , int port , int dev ,
u16 data )
{
u16 op = MV88E6XXX_G2_SMI_PHY_CMD_OP_45_WRITE_DATA ;
int err ;
2016-09-02 14:45:33 -04:00
2017-06-19 10:55:37 -04:00
err = mv88e6xxx_g2_write ( chip , MV88E6XXX_G2_SMI_PHY_DATA , data ) ;
2016-09-02 14:45:33 -04:00
if ( err )
return err ;
2017-06-19 10:55:37 -04:00
return mv88e6xxx_g2_smi_phy_access_c45 ( chip , external , op , port , dev ) ;
2016-09-02 14:45:33 -04:00
}
2017-06-19 10:55:37 -04:00
static int mv88e6xxx_g2_smi_phy_write_c45 ( struct mv88e6xxx_chip * chip ,
bool external , int port , int reg ,
u16 data )
2016-09-02 14:45:33 -04:00
{
2017-06-19 10:55:37 -04:00
int dev = ( reg > > 16 ) & 0x1f ;
int addr = reg & 0xffff ;
2016-09-02 14:45:33 -04:00
int err ;
2017-06-19 10:55:37 -04:00
err = mv88e6xxx_g2_smi_phy_write_addr_c45 ( chip , external , port , dev ,
addr ) ;
2016-09-02 14:45:33 -04:00
if ( err )
return err ;
2017-06-19 10:55:37 -04:00
return mv88e6xxx_g2_smi_phy_write_data_c45 ( chip , external , port , dev ,
data ) ;
}
2016-09-02 14:45:33 -04:00
2017-06-19 10:55:37 -04:00
int mv88e6xxx_g2_smi_phy_read ( struct mv88e6xxx_chip * chip , struct mii_bus * bus ,
int addr , int reg , u16 * val )
{
struct mv88e6xxx_mdio_bus * mdio_bus = bus - > priv ;
bool external = mdio_bus - > external ;
if ( reg & MII_ADDR_C45 )
return mv88e6xxx_g2_smi_phy_read_c45 ( chip , external , addr , reg ,
val ) ;
return mv88e6xxx_g2_smi_phy_read_data_c22 ( chip , external , addr , reg ,
val ) ;
2016-09-02 14:45:33 -04:00
}
2017-06-19 10:55:37 -04:00
int mv88e6xxx_g2_smi_phy_write ( struct mv88e6xxx_chip * chip , struct mii_bus * bus ,
2017-02-04 20:12:24 +01:00
int addr , int reg , u16 val )
{
struct mv88e6xxx_mdio_bus * mdio_bus = bus - > priv ;
bool external = mdio_bus - > external ;
if ( reg & MII_ADDR_C45 )
2017-06-19 10:55:37 -04:00
return mv88e6xxx_g2_smi_phy_write_c45 ( chip , external , addr , reg ,
val ) ;
2017-02-04 20:12:24 +01:00
2017-06-19 10:55:37 -04:00
return mv88e6xxx_g2_smi_phy_write_data_c22 ( chip , external , addr , reg ,
val ) ;
2017-02-04 20:12:24 +01:00
}
2018-02-14 01:07:46 +01:00
/* Offset 0x1B: Watchdog Control */
2017-02-09 00:03:42 +01:00
static int mv88e6097_watchdog_action ( struct mv88e6xxx_chip * chip , int irq )
{
u16 reg ;
2017-06-19 10:55:44 -04:00
mv88e6xxx_g2_read ( chip , MV88E6352_G2_WDOG_CTL , & reg ) ;
2017-02-09 00:03:42 +01:00
dev_info ( chip - > dev , " Watchdog event: 0x%04x " , reg ) ;
return IRQ_HANDLED ;
}
static void mv88e6097_watchdog_free ( struct mv88e6xxx_chip * chip )
{
u16 reg ;
2017-06-19 10:55:44 -04:00
mv88e6xxx_g2_read ( chip , MV88E6352_G2_WDOG_CTL , & reg ) ;
2017-02-09 00:03:42 +01:00
2017-06-19 10:55:44 -04:00
reg & = ~ ( MV88E6352_G2_WDOG_CTL_EGRESS_ENABLE |
MV88E6352_G2_WDOG_CTL_QC_ENABLE ) ;
2017-02-09 00:03:42 +01:00
2017-06-19 10:55:44 -04:00
mv88e6xxx_g2_write ( chip , MV88E6352_G2_WDOG_CTL , reg ) ;
2017-02-09 00:03:42 +01:00
}
static int mv88e6097_watchdog_setup ( struct mv88e6xxx_chip * chip )
{
2017-06-19 10:55:44 -04:00
return mv88e6xxx_g2_write ( chip , MV88E6352_G2_WDOG_CTL ,
MV88E6352_G2_WDOG_CTL_EGRESS_ENABLE |
MV88E6352_G2_WDOG_CTL_QC_ENABLE |
MV88E6352_G2_WDOG_CTL_SWRESET ) ;
2017-02-09 00:03:42 +01:00
}
const struct mv88e6xxx_irq_ops mv88e6097_watchdog_ops = {
. irq_action = mv88e6097_watchdog_action ,
. irq_setup = mv88e6097_watchdog_setup ,
. irq_free = mv88e6097_watchdog_free ,
} ;
2019-06-04 07:34:28 +00:00
static void mv88e6250_watchdog_free ( struct mv88e6xxx_chip * chip )
{
u16 reg ;
mv88e6xxx_g2_read ( chip , MV88E6250_G2_WDOG_CTL , & reg ) ;
reg & = ~ ( MV88E6250_G2_WDOG_CTL_EGRESS_ENABLE |
MV88E6250_G2_WDOG_CTL_QC_ENABLE ) ;
mv88e6xxx_g2_write ( chip , MV88E6250_G2_WDOG_CTL , reg ) ;
}
static int mv88e6250_watchdog_setup ( struct mv88e6xxx_chip * chip )
{
return mv88e6xxx_g2_write ( chip , MV88E6250_G2_WDOG_CTL ,
MV88E6250_G2_WDOG_CTL_EGRESS_ENABLE |
MV88E6250_G2_WDOG_CTL_QC_ENABLE |
MV88E6250_G2_WDOG_CTL_SWRESET ) ;
}
const struct mv88e6xxx_irq_ops mv88e6250_watchdog_ops = {
. irq_action = mv88e6097_watchdog_action ,
. irq_setup = mv88e6250_watchdog_setup ,
. irq_free = mv88e6250_watchdog_free ,
} ;
2017-02-09 00:03:43 +01:00
static int mv88e6390_watchdog_setup ( struct mv88e6xxx_chip * chip )
{
2019-08-09 18:47:57 -04:00
return mv88e6xxx_g2_write ( chip , MV88E6390_G2_WDOG_CTL ,
MV88E6390_G2_WDOG_CTL_UPDATE |
MV88E6390_G2_WDOG_CTL_PTR_INT_ENABLE |
MV88E6390_G2_WDOG_CTL_CUT_THROUGH |
MV88E6390_G2_WDOG_CTL_QUEUE_CONTROLLER |
MV88E6390_G2_WDOG_CTL_EGRESS |
MV88E6390_G2_WDOG_CTL_FORCE_IRQ ) ;
2017-02-09 00:03:43 +01:00
}
static int mv88e6390_watchdog_action ( struct mv88e6xxx_chip * chip , int irq )
{
u16 reg ;
2017-06-19 10:55:44 -04:00
mv88e6xxx_g2_write ( chip , MV88E6390_G2_WDOG_CTL ,
MV88E6390_G2_WDOG_CTL_PTR_EVENT ) ;
2020-07-05 21:38:09 +02:00
mv88e6xxx_g2_read ( chip , MV88E6390_G2_WDOG_CTL , & reg ) ;
2017-02-09 00:03:43 +01:00
dev_info ( chip - > dev , " Watchdog event: 0x%04x " ,
2017-06-19 10:55:44 -04:00
reg & MV88E6390_G2_WDOG_CTL_DATA_MASK ) ;
2017-02-09 00:03:43 +01:00
2017-06-19 10:55:44 -04:00
mv88e6xxx_g2_write ( chip , MV88E6390_G2_WDOG_CTL ,
MV88E6390_G2_WDOG_CTL_PTR_HISTORY ) ;
2020-07-05 21:38:09 +02:00
mv88e6xxx_g2_read ( chip , MV88E6390_G2_WDOG_CTL , & reg ) ;
2017-02-09 00:03:43 +01:00
dev_info ( chip - > dev , " Watchdog history: 0x%04x " ,
2017-06-19 10:55:44 -04:00
reg & MV88E6390_G2_WDOG_CTL_DATA_MASK ) ;
2017-02-09 00:03:43 +01:00
/* Trigger a software reset to try to recover the switch */
if ( chip - > info - > ops - > reset )
chip - > info - > ops - > reset ( chip ) ;
mv88e6390_watchdog_setup ( chip ) ;
return IRQ_HANDLED ;
}
static void mv88e6390_watchdog_free ( struct mv88e6xxx_chip * chip )
{
2019-08-09 18:47:57 -04:00
mv88e6xxx_g2_write ( chip , MV88E6390_G2_WDOG_CTL ,
MV88E6390_G2_WDOG_CTL_UPDATE |
MV88E6390_G2_WDOG_CTL_PTR_INT_ENABLE ) ;
2017-02-09 00:03:43 +01:00
}
const struct mv88e6xxx_irq_ops mv88e6390_watchdog_ops = {
. irq_action = mv88e6390_watchdog_action ,
. irq_setup = mv88e6390_watchdog_setup ,
. irq_free = mv88e6390_watchdog_free ,
} ;
2017-02-09 00:03:42 +01:00
static irqreturn_t mv88e6xxx_g2_watchdog_thread_fn ( int irq , void * dev_id )
{
struct mv88e6xxx_chip * chip = dev_id ;
irqreturn_t ret = IRQ_NONE ;
2019-06-20 13:50:42 +00:00
mv88e6xxx_reg_lock ( chip ) ;
2017-02-09 00:03:42 +01:00
if ( chip - > info - > ops - > watchdog_ops - > irq_action )
ret = chip - > info - > ops - > watchdog_ops - > irq_action ( chip , irq ) ;
2019-06-20 13:50:42 +00:00
mv88e6xxx_reg_unlock ( chip ) ;
2017-02-09 00:03:42 +01:00
return ret ;
}
static void mv88e6xxx_g2_watchdog_free ( struct mv88e6xxx_chip * chip )
{
2019-06-20 13:50:42 +00:00
mv88e6xxx_reg_lock ( chip ) ;
2017-02-09 00:03:42 +01:00
if ( chip - > info - > ops - > watchdog_ops - > irq_free )
chip - > info - > ops - > watchdog_ops - > irq_free ( chip ) ;
2019-06-20 13:50:42 +00:00
mv88e6xxx_reg_unlock ( chip ) ;
2017-02-09 00:03:42 +01:00
free_irq ( chip - > watchdog_irq , chip ) ;
irq_dispose_mapping ( chip - > watchdog_irq ) ;
}
static int mv88e6xxx_g2_watchdog_setup ( struct mv88e6xxx_chip * chip )
{
int err ;
chip - > watchdog_irq = irq_find_mapping ( chip - > g2_irq . domain ,
2017-06-19 10:55:45 -04:00
MV88E6XXX_G2_INT_SOURCE_WATCHDOG ) ;
2017-02-09 00:03:42 +01:00
if ( chip - > watchdog_irq < 0 )
return chip - > watchdog_irq ;
2020-01-06 17:13:50 +01:00
snprintf ( chip - > watchdog_irq_name , sizeof ( chip - > watchdog_irq_name ) ,
" mv88e6xxx-%s-watchdog " , dev_name ( chip - > dev ) ) ;
2017-02-09 00:03:42 +01:00
err = request_threaded_irq ( chip - > watchdog_irq , NULL ,
mv88e6xxx_g2_watchdog_thread_fn ,
IRQF_ONESHOT | IRQF_TRIGGER_FALLING ,
2020-01-06 17:13:50 +01:00
chip - > watchdog_irq_name , chip ) ;
2017-02-09 00:03:42 +01:00
if ( err )
return err ;
2019-06-20 13:50:42 +00:00
mv88e6xxx_reg_lock ( chip ) ;
2017-02-09 00:03:42 +01:00
if ( chip - > info - > ops - > watchdog_ops - > irq_setup )
err = chip - > info - > ops - > watchdog_ops - > irq_setup ( chip ) ;
2019-06-20 13:50:42 +00:00
mv88e6xxx_reg_unlock ( chip ) ;
2017-02-09 00:03:42 +01:00
return err ;
}
2017-03-30 17:37:08 -04:00
/* Offset 0x1D: Misc Register */
static int mv88e6xxx_g2_misc_5_bit_port ( struct mv88e6xxx_chip * chip ,
bool port_5_bit )
{
u16 val ;
int err ;
2017-06-19 10:55:45 -04:00
err = mv88e6xxx_g2_read ( chip , MV88E6XXX_G2_MISC , & val ) ;
2017-03-30 17:37:08 -04:00
if ( err )
return err ;
if ( port_5_bit )
2017-06-19 10:55:45 -04:00
val | = MV88E6XXX_G2_MISC_5_BIT_PORT ;
2017-03-30 17:37:08 -04:00
else
2017-06-19 10:55:45 -04:00
val & = ~ MV88E6XXX_G2_MISC_5_BIT_PORT ;
2017-03-30 17:37:08 -04:00
2017-06-19 10:55:45 -04:00
return mv88e6xxx_g2_write ( chip , MV88E6XXX_G2_MISC , val ) ;
2017-03-30 17:37:08 -04:00
}
int mv88e6xxx_g2_misc_4_bit_port ( struct mv88e6xxx_chip * chip )
{
return mv88e6xxx_g2_misc_5_bit_port ( chip , false ) ;
}
2016-10-16 19:56:49 +02:00
static void mv88e6xxx_g2_irq_mask ( struct irq_data * d )
{
struct mv88e6xxx_chip * chip = irq_data_get_irq_chip_data ( d ) ;
unsigned int n = d - > hwirq ;
chip - > g2_irq . masked | = ( 1 < < n ) ;
}
static void mv88e6xxx_g2_irq_unmask ( struct irq_data * d )
{
struct mv88e6xxx_chip * chip = irq_data_get_irq_chip_data ( d ) ;
unsigned int n = d - > hwirq ;
chip - > g2_irq . masked & = ~ ( 1 < < n ) ;
}
static irqreturn_t mv88e6xxx_g2_irq_thread_fn ( int irq , void * dev_id )
{
struct mv88e6xxx_chip * chip = dev_id ;
unsigned int nhandled = 0 ;
unsigned int sub_irq ;
unsigned int n ;
int err ;
u16 reg ;
2019-06-20 13:50:42 +00:00
mv88e6xxx_reg_lock ( chip ) ;
2017-07-17 13:03:40 -04:00
err = mv88e6xxx_g2_int_source ( chip , & reg ) ;
2019-06-20 13:50:42 +00:00
mv88e6xxx_reg_unlock ( chip ) ;
2016-10-16 19:56:49 +02:00
if ( err )
goto out ;
for ( n = 0 ; n < 16 ; + + n ) {
if ( reg & ( 1 < < n ) ) {
sub_irq = irq_find_mapping ( chip - > g2_irq . domain , n ) ;
handle_nested_irq ( sub_irq ) ;
+ + nhandled ;
}
}
out :
return ( nhandled > 0 ? IRQ_HANDLED : IRQ_NONE ) ;
}
static void mv88e6xxx_g2_irq_bus_lock ( struct irq_data * d )
{
struct mv88e6xxx_chip * chip = irq_data_get_irq_chip_data ( d ) ;
2019-06-20 13:50:42 +00:00
mv88e6xxx_reg_lock ( chip ) ;
2016-10-16 19:56:49 +02:00
}
static void mv88e6xxx_g2_irq_bus_sync_unlock ( struct irq_data * d )
{
struct mv88e6xxx_chip * chip = irq_data_get_irq_chip_data ( d ) ;
2017-07-17 13:03:40 -04:00
int err ;
2016-10-16 19:56:49 +02:00
2017-07-17 13:03:40 -04:00
err = mv88e6xxx_g2_int_mask ( chip , ~ chip - > g2_irq . masked ) ;
if ( err )
dev_err ( chip - > dev , " failed to mask interrupts \n " ) ;
2016-10-16 19:56:49 +02:00
2019-06-20 13:50:42 +00:00
mv88e6xxx_reg_unlock ( chip ) ;
2016-10-16 19:56:49 +02:00
}
2017-08-19 16:25:52 +05:30
static const struct irq_chip mv88e6xxx_g2_irq_chip = {
2016-10-16 19:56:49 +02:00
. name = " mv88e6xxx-g2 " ,
. irq_mask = mv88e6xxx_g2_irq_mask ,
. irq_unmask = mv88e6xxx_g2_irq_unmask ,
. irq_bus_lock = mv88e6xxx_g2_irq_bus_lock ,
. irq_bus_sync_unlock = mv88e6xxx_g2_irq_bus_sync_unlock ,
} ;
static int mv88e6xxx_g2_irq_domain_map ( struct irq_domain * d ,
unsigned int irq ,
irq_hw_number_t hwirq )
{
struct mv88e6xxx_chip * chip = d - > host_data ;
irq_set_chip_data ( irq , d - > host_data ) ;
irq_set_chip_and_handler ( irq , & chip - > g2_irq . chip , handle_level_irq ) ;
irq_set_noprobe ( irq ) ;
return 0 ;
}
static const struct irq_domain_ops mv88e6xxx_g2_irq_domain_ops = {
. map = mv88e6xxx_g2_irq_domain_map ,
. xlate = irq_domain_xlate_twocell ,
} ;
void mv88e6xxx_g2_irq_free ( struct mv88e6xxx_chip * chip )
{
int irq , virq ;
2017-02-09 00:03:42 +01:00
mv88e6xxx_g2_watchdog_free ( chip ) ;
2016-11-20 20:14:18 +01:00
free_irq ( chip - > device_irq , chip ) ;
irq_dispose_mapping ( chip - > device_irq ) ;
2016-10-16 19:56:49 +02:00
for ( irq = 0 ; irq < 16 ; irq + + ) {
virq = irq_find_mapping ( chip - > g2_irq . domain , irq ) ;
irq_dispose_mapping ( virq ) ;
}
irq_domain_remove ( chip - > g2_irq . domain ) ;
}
int mv88e6xxx_g2_irq_setup ( struct mv88e6xxx_chip * chip )
{
2016-11-20 20:14:18 +01:00
int err , irq , virq ;
2016-10-16 19:56:49 +02:00
2020-02-28 19:39:41 +00:00
chip - > g2_irq . masked = ~ 0 ;
mv88e6xxx_reg_lock ( chip ) ;
err = mv88e6xxx_g2_int_mask ( chip , ~ chip - > g2_irq . masked ) ;
mv88e6xxx_reg_unlock ( chip ) ;
if ( err )
return err ;
2016-10-16 19:56:49 +02:00
chip - > g2_irq . domain = irq_domain_add_simple (
chip - > dev - > of_node , 16 , 0 , & mv88e6xxx_g2_irq_domain_ops , chip ) ;
if ( ! chip - > g2_irq . domain )
return - ENOMEM ;
for ( irq = 0 ; irq < 16 ; irq + + )
irq_create_mapping ( chip - > g2_irq . domain , irq ) ;
chip - > g2_irq . chip = mv88e6xxx_g2_irq_chip ;
2016-11-20 20:14:18 +01:00
chip - > device_irq = irq_find_mapping ( chip - > g1_irq . domain ,
2017-06-15 12:13:59 -04:00
MV88E6XXX_G1_STS_IRQ_DEVICE ) ;
2016-11-20 20:14:18 +01:00
if ( chip - > device_irq < 0 ) {
err = chip - > device_irq ;
2016-10-16 19:56:49 +02:00
goto out ;
}
2020-01-06 17:13:51 +01:00
snprintf ( chip - > device_irq_name , sizeof ( chip - > device_irq_name ) ,
" mv88e6xxx-%s-g2 " , dev_name ( chip - > dev ) ) ;
2016-11-20 20:14:18 +01:00
err = request_threaded_irq ( chip - > device_irq , NULL ,
mv88e6xxx_g2_irq_thread_fn ,
2020-01-06 17:13:51 +01:00
IRQF_ONESHOT , chip - > device_irq_name , chip ) ;
2016-10-16 19:56:49 +02:00
if ( err )
goto out ;
2017-02-09 00:03:42 +01:00
return mv88e6xxx_g2_watchdog_setup ( chip ) ;
2016-11-20 20:14:18 +01:00
2016-10-16 19:56:49 +02:00
out :
2016-11-20 20:14:18 +01:00
for ( irq = 0 ; irq < 16 ; irq + + ) {
virq = irq_find_mapping ( chip - > g2_irq . domain , irq ) ;
irq_dispose_mapping ( virq ) ;
}
irq_domain_remove ( chip - > g2_irq . domain ) ;
2016-10-16 19:56:49 +02:00
return err ;
}
2018-03-17 20:32:05 +01:00
int mv88e6xxx_g2_irq_mdio_setup ( struct mv88e6xxx_chip * chip ,
struct mii_bus * bus )
{
int phy , irq , err , err_phy ;
for ( phy = 0 ; phy < chip - > info - > num_internal_phys ; phy + + ) {
irq = irq_find_mapping ( chip - > g2_irq . domain , phy ) ;
if ( irq < 0 ) {
err = irq ;
goto out ;
}
2018-05-05 20:58:22 +02:00
bus - > irq [ chip - > info - > phy_base_addr + phy ] = irq ;
2018-03-17 20:32:05 +01:00
}
return 0 ;
out :
err_phy = phy ;
for ( phy = 0 ; phy < err_phy ; phy + + )
irq_dispose_mapping ( bus - > irq [ phy ] ) ;
return err ;
}
void mv88e6xxx_g2_irq_mdio_free ( struct mv88e6xxx_chip * chip ,
struct mii_bus * bus )
{
int phy ;
for ( phy = 0 ; phy < chip - > info - > num_internal_phys ; phy + + )
irq_dispose_mapping ( bus - > irq [ phy ] ) ;
}