162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Microchip switch driver main logic 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (C) 2017-2019 Microchip Technology Inc. 662306a36Sopenharmony_ci */ 762306a36Sopenharmony_ci 862306a36Sopenharmony_ci#include <linux/delay.h> 962306a36Sopenharmony_ci#include <linux/dsa/ksz_common.h> 1062306a36Sopenharmony_ci#include <linux/export.h> 1162306a36Sopenharmony_ci#include <linux/gpio/consumer.h> 1262306a36Sopenharmony_ci#include <linux/kernel.h> 1362306a36Sopenharmony_ci#include <linux/module.h> 1462306a36Sopenharmony_ci#include <linux/platform_data/microchip-ksz.h> 1562306a36Sopenharmony_ci#include <linux/phy.h> 1662306a36Sopenharmony_ci#include <linux/etherdevice.h> 1762306a36Sopenharmony_ci#include <linux/if_bridge.h> 1862306a36Sopenharmony_ci#include <linux/if_vlan.h> 1962306a36Sopenharmony_ci#include <linux/irq.h> 2062306a36Sopenharmony_ci#include <linux/irqdomain.h> 2162306a36Sopenharmony_ci#include <linux/of.h> 2262306a36Sopenharmony_ci#include <linux/of_mdio.h> 2362306a36Sopenharmony_ci#include <linux/of_net.h> 2462306a36Sopenharmony_ci#include <linux/micrel_phy.h> 2562306a36Sopenharmony_ci#include <net/dsa.h> 2662306a36Sopenharmony_ci#include <net/pkt_cls.h> 2762306a36Sopenharmony_ci#include <net/switchdev.h> 2862306a36Sopenharmony_ci 2962306a36Sopenharmony_ci#include "ksz_common.h" 3062306a36Sopenharmony_ci#include "ksz_ptp.h" 3162306a36Sopenharmony_ci#include "ksz8.h" 3262306a36Sopenharmony_ci#include "ksz9477.h" 3362306a36Sopenharmony_ci#include "lan937x.h" 3462306a36Sopenharmony_ci 3562306a36Sopenharmony_ci#define MIB_COUNTER_NUM 0x20 3662306a36Sopenharmony_ci 3762306a36Sopenharmony_cistruct ksz_stats_raw { 3862306a36Sopenharmony_ci u64 rx_hi; 3962306a36Sopenharmony_ci u64 rx_undersize; 4062306a36Sopenharmony_ci u64 rx_fragments; 4162306a36Sopenharmony_ci u64 rx_oversize; 4262306a36Sopenharmony_ci u64 rx_jabbers; 4362306a36Sopenharmony_ci u64 rx_symbol_err; 4462306a36Sopenharmony_ci u64 rx_crc_err; 4562306a36Sopenharmony_ci u64 rx_align_err; 4662306a36Sopenharmony_ci u64 rx_mac_ctrl; 4762306a36Sopenharmony_ci u64 rx_pause; 4862306a36Sopenharmony_ci u64 rx_bcast; 4962306a36Sopenharmony_ci u64 rx_mcast; 5062306a36Sopenharmony_ci u64 rx_ucast; 5162306a36Sopenharmony_ci u64 rx_64_or_less; 5262306a36Sopenharmony_ci u64 rx_65_127; 5362306a36Sopenharmony_ci u64 rx_128_255; 5462306a36Sopenharmony_ci u64 rx_256_511; 5562306a36Sopenharmony_ci u64 rx_512_1023; 5662306a36Sopenharmony_ci u64 rx_1024_1522; 5762306a36Sopenharmony_ci u64 rx_1523_2000; 5862306a36Sopenharmony_ci u64 rx_2001; 5962306a36Sopenharmony_ci u64 tx_hi; 6062306a36Sopenharmony_ci u64 tx_late_col; 6162306a36Sopenharmony_ci u64 tx_pause; 6262306a36Sopenharmony_ci u64 tx_bcast; 6362306a36Sopenharmony_ci u64 tx_mcast; 6462306a36Sopenharmony_ci u64 tx_ucast; 6562306a36Sopenharmony_ci u64 tx_deferred; 6662306a36Sopenharmony_ci u64 tx_total_col; 6762306a36Sopenharmony_ci u64 tx_exc_col; 6862306a36Sopenharmony_ci u64 tx_single_col; 6962306a36Sopenharmony_ci u64 tx_mult_col; 7062306a36Sopenharmony_ci u64 rx_total; 7162306a36Sopenharmony_ci u64 tx_total; 7262306a36Sopenharmony_ci u64 rx_discards; 7362306a36Sopenharmony_ci u64 tx_discards; 7462306a36Sopenharmony_ci}; 7562306a36Sopenharmony_ci 7662306a36Sopenharmony_cistruct ksz88xx_stats_raw { 7762306a36Sopenharmony_ci u64 rx; 7862306a36Sopenharmony_ci u64 rx_hi; 7962306a36Sopenharmony_ci u64 rx_undersize; 8062306a36Sopenharmony_ci u64 rx_fragments; 8162306a36Sopenharmony_ci u64 rx_oversize; 8262306a36Sopenharmony_ci u64 rx_jabbers; 8362306a36Sopenharmony_ci u64 rx_symbol_err; 8462306a36Sopenharmony_ci u64 rx_crc_err; 8562306a36Sopenharmony_ci u64 rx_align_err; 8662306a36Sopenharmony_ci u64 rx_mac_ctrl; 8762306a36Sopenharmony_ci u64 rx_pause; 8862306a36Sopenharmony_ci u64 rx_bcast; 8962306a36Sopenharmony_ci u64 rx_mcast; 9062306a36Sopenharmony_ci u64 rx_ucast; 9162306a36Sopenharmony_ci u64 rx_64_or_less; 9262306a36Sopenharmony_ci u64 rx_65_127; 9362306a36Sopenharmony_ci u64 rx_128_255; 9462306a36Sopenharmony_ci u64 rx_256_511; 9562306a36Sopenharmony_ci u64 rx_512_1023; 9662306a36Sopenharmony_ci u64 rx_1024_1522; 9762306a36Sopenharmony_ci u64 tx; 9862306a36Sopenharmony_ci u64 tx_hi; 9962306a36Sopenharmony_ci u64 tx_late_col; 10062306a36Sopenharmony_ci u64 tx_pause; 10162306a36Sopenharmony_ci u64 tx_bcast; 10262306a36Sopenharmony_ci u64 tx_mcast; 10362306a36Sopenharmony_ci u64 tx_ucast; 10462306a36Sopenharmony_ci u64 tx_deferred; 10562306a36Sopenharmony_ci u64 tx_total_col; 10662306a36Sopenharmony_ci u64 tx_exc_col; 10762306a36Sopenharmony_ci u64 tx_single_col; 10862306a36Sopenharmony_ci u64 tx_mult_col; 10962306a36Sopenharmony_ci u64 rx_discards; 11062306a36Sopenharmony_ci u64 tx_discards; 11162306a36Sopenharmony_ci}; 11262306a36Sopenharmony_ci 11362306a36Sopenharmony_cistatic const struct ksz_mib_names ksz88xx_mib_names[] = { 11462306a36Sopenharmony_ci { 0x00, "rx" }, 11562306a36Sopenharmony_ci { 0x01, "rx_hi" }, 11662306a36Sopenharmony_ci { 0x02, "rx_undersize" }, 11762306a36Sopenharmony_ci { 0x03, "rx_fragments" }, 11862306a36Sopenharmony_ci { 0x04, "rx_oversize" }, 11962306a36Sopenharmony_ci { 0x05, "rx_jabbers" }, 12062306a36Sopenharmony_ci { 0x06, "rx_symbol_err" }, 12162306a36Sopenharmony_ci { 0x07, "rx_crc_err" }, 12262306a36Sopenharmony_ci { 0x08, "rx_align_err" }, 12362306a36Sopenharmony_ci { 0x09, "rx_mac_ctrl" }, 12462306a36Sopenharmony_ci { 0x0a, "rx_pause" }, 12562306a36Sopenharmony_ci { 0x0b, "rx_bcast" }, 12662306a36Sopenharmony_ci { 0x0c, "rx_mcast" }, 12762306a36Sopenharmony_ci { 0x0d, "rx_ucast" }, 12862306a36Sopenharmony_ci { 0x0e, "rx_64_or_less" }, 12962306a36Sopenharmony_ci { 0x0f, "rx_65_127" }, 13062306a36Sopenharmony_ci { 0x10, "rx_128_255" }, 13162306a36Sopenharmony_ci { 0x11, "rx_256_511" }, 13262306a36Sopenharmony_ci { 0x12, "rx_512_1023" }, 13362306a36Sopenharmony_ci { 0x13, "rx_1024_1522" }, 13462306a36Sopenharmony_ci { 0x14, "tx" }, 13562306a36Sopenharmony_ci { 0x15, "tx_hi" }, 13662306a36Sopenharmony_ci { 0x16, "tx_late_col" }, 13762306a36Sopenharmony_ci { 0x17, "tx_pause" }, 13862306a36Sopenharmony_ci { 0x18, "tx_bcast" }, 13962306a36Sopenharmony_ci { 0x19, "tx_mcast" }, 14062306a36Sopenharmony_ci { 0x1a, "tx_ucast" }, 14162306a36Sopenharmony_ci { 0x1b, "tx_deferred" }, 14262306a36Sopenharmony_ci { 0x1c, "tx_total_col" }, 14362306a36Sopenharmony_ci { 0x1d, "tx_exc_col" }, 14462306a36Sopenharmony_ci { 0x1e, "tx_single_col" }, 14562306a36Sopenharmony_ci { 0x1f, "tx_mult_col" }, 14662306a36Sopenharmony_ci { 0x100, "rx_discards" }, 14762306a36Sopenharmony_ci { 0x101, "tx_discards" }, 14862306a36Sopenharmony_ci}; 14962306a36Sopenharmony_ci 15062306a36Sopenharmony_cistatic const struct ksz_mib_names ksz9477_mib_names[] = { 15162306a36Sopenharmony_ci { 0x00, "rx_hi" }, 15262306a36Sopenharmony_ci { 0x01, "rx_undersize" }, 15362306a36Sopenharmony_ci { 0x02, "rx_fragments" }, 15462306a36Sopenharmony_ci { 0x03, "rx_oversize" }, 15562306a36Sopenharmony_ci { 0x04, "rx_jabbers" }, 15662306a36Sopenharmony_ci { 0x05, "rx_symbol_err" }, 15762306a36Sopenharmony_ci { 0x06, "rx_crc_err" }, 15862306a36Sopenharmony_ci { 0x07, "rx_align_err" }, 15962306a36Sopenharmony_ci { 0x08, "rx_mac_ctrl" }, 16062306a36Sopenharmony_ci { 0x09, "rx_pause" }, 16162306a36Sopenharmony_ci { 0x0A, "rx_bcast" }, 16262306a36Sopenharmony_ci { 0x0B, "rx_mcast" }, 16362306a36Sopenharmony_ci { 0x0C, "rx_ucast" }, 16462306a36Sopenharmony_ci { 0x0D, "rx_64_or_less" }, 16562306a36Sopenharmony_ci { 0x0E, "rx_65_127" }, 16662306a36Sopenharmony_ci { 0x0F, "rx_128_255" }, 16762306a36Sopenharmony_ci { 0x10, "rx_256_511" }, 16862306a36Sopenharmony_ci { 0x11, "rx_512_1023" }, 16962306a36Sopenharmony_ci { 0x12, "rx_1024_1522" }, 17062306a36Sopenharmony_ci { 0x13, "rx_1523_2000" }, 17162306a36Sopenharmony_ci { 0x14, "rx_2001" }, 17262306a36Sopenharmony_ci { 0x15, "tx_hi" }, 17362306a36Sopenharmony_ci { 0x16, "tx_late_col" }, 17462306a36Sopenharmony_ci { 0x17, "tx_pause" }, 17562306a36Sopenharmony_ci { 0x18, "tx_bcast" }, 17662306a36Sopenharmony_ci { 0x19, "tx_mcast" }, 17762306a36Sopenharmony_ci { 0x1A, "tx_ucast" }, 17862306a36Sopenharmony_ci { 0x1B, "tx_deferred" }, 17962306a36Sopenharmony_ci { 0x1C, "tx_total_col" }, 18062306a36Sopenharmony_ci { 0x1D, "tx_exc_col" }, 18162306a36Sopenharmony_ci { 0x1E, "tx_single_col" }, 18262306a36Sopenharmony_ci { 0x1F, "tx_mult_col" }, 18362306a36Sopenharmony_ci { 0x80, "rx_total" }, 18462306a36Sopenharmony_ci { 0x81, "tx_total" }, 18562306a36Sopenharmony_ci { 0x82, "rx_discards" }, 18662306a36Sopenharmony_ci { 0x83, "tx_discards" }, 18762306a36Sopenharmony_ci}; 18862306a36Sopenharmony_ci 18962306a36Sopenharmony_cistatic const struct ksz_dev_ops ksz8_dev_ops = { 19062306a36Sopenharmony_ci .setup = ksz8_setup, 19162306a36Sopenharmony_ci .get_port_addr = ksz8_get_port_addr, 19262306a36Sopenharmony_ci .cfg_port_member = ksz8_cfg_port_member, 19362306a36Sopenharmony_ci .flush_dyn_mac_table = ksz8_flush_dyn_mac_table, 19462306a36Sopenharmony_ci .port_setup = ksz8_port_setup, 19562306a36Sopenharmony_ci .r_phy = ksz8_r_phy, 19662306a36Sopenharmony_ci .w_phy = ksz8_w_phy, 19762306a36Sopenharmony_ci .r_mib_cnt = ksz8_r_mib_cnt, 19862306a36Sopenharmony_ci .r_mib_pkt = ksz8_r_mib_pkt, 19962306a36Sopenharmony_ci .r_mib_stat64 = ksz88xx_r_mib_stats64, 20062306a36Sopenharmony_ci .freeze_mib = ksz8_freeze_mib, 20162306a36Sopenharmony_ci .port_init_cnt = ksz8_port_init_cnt, 20262306a36Sopenharmony_ci .fdb_dump = ksz8_fdb_dump, 20362306a36Sopenharmony_ci .fdb_add = ksz8_fdb_add, 20462306a36Sopenharmony_ci .fdb_del = ksz8_fdb_del, 20562306a36Sopenharmony_ci .mdb_add = ksz8_mdb_add, 20662306a36Sopenharmony_ci .mdb_del = ksz8_mdb_del, 20762306a36Sopenharmony_ci .vlan_filtering = ksz8_port_vlan_filtering, 20862306a36Sopenharmony_ci .vlan_add = ksz8_port_vlan_add, 20962306a36Sopenharmony_ci .vlan_del = ksz8_port_vlan_del, 21062306a36Sopenharmony_ci .mirror_add = ksz8_port_mirror_add, 21162306a36Sopenharmony_ci .mirror_del = ksz8_port_mirror_del, 21262306a36Sopenharmony_ci .get_caps = ksz8_get_caps, 21362306a36Sopenharmony_ci .config_cpu_port = ksz8_config_cpu_port, 21462306a36Sopenharmony_ci .enable_stp_addr = ksz8_enable_stp_addr, 21562306a36Sopenharmony_ci .reset = ksz8_reset_switch, 21662306a36Sopenharmony_ci .init = ksz8_switch_init, 21762306a36Sopenharmony_ci .exit = ksz8_switch_exit, 21862306a36Sopenharmony_ci .change_mtu = ksz8_change_mtu, 21962306a36Sopenharmony_ci}; 22062306a36Sopenharmony_ci 22162306a36Sopenharmony_cistatic void ksz9477_phylink_mac_link_up(struct ksz_device *dev, int port, 22262306a36Sopenharmony_ci unsigned int mode, 22362306a36Sopenharmony_ci phy_interface_t interface, 22462306a36Sopenharmony_ci struct phy_device *phydev, int speed, 22562306a36Sopenharmony_ci int duplex, bool tx_pause, 22662306a36Sopenharmony_ci bool rx_pause); 22762306a36Sopenharmony_ci 22862306a36Sopenharmony_cistatic const struct ksz_dev_ops ksz9477_dev_ops = { 22962306a36Sopenharmony_ci .setup = ksz9477_setup, 23062306a36Sopenharmony_ci .get_port_addr = ksz9477_get_port_addr, 23162306a36Sopenharmony_ci .cfg_port_member = ksz9477_cfg_port_member, 23262306a36Sopenharmony_ci .flush_dyn_mac_table = ksz9477_flush_dyn_mac_table, 23362306a36Sopenharmony_ci .port_setup = ksz9477_port_setup, 23462306a36Sopenharmony_ci .set_ageing_time = ksz9477_set_ageing_time, 23562306a36Sopenharmony_ci .r_phy = ksz9477_r_phy, 23662306a36Sopenharmony_ci .w_phy = ksz9477_w_phy, 23762306a36Sopenharmony_ci .r_mib_cnt = ksz9477_r_mib_cnt, 23862306a36Sopenharmony_ci .r_mib_pkt = ksz9477_r_mib_pkt, 23962306a36Sopenharmony_ci .r_mib_stat64 = ksz_r_mib_stats64, 24062306a36Sopenharmony_ci .freeze_mib = ksz9477_freeze_mib, 24162306a36Sopenharmony_ci .port_init_cnt = ksz9477_port_init_cnt, 24262306a36Sopenharmony_ci .vlan_filtering = ksz9477_port_vlan_filtering, 24362306a36Sopenharmony_ci .vlan_add = ksz9477_port_vlan_add, 24462306a36Sopenharmony_ci .vlan_del = ksz9477_port_vlan_del, 24562306a36Sopenharmony_ci .mirror_add = ksz9477_port_mirror_add, 24662306a36Sopenharmony_ci .mirror_del = ksz9477_port_mirror_del, 24762306a36Sopenharmony_ci .get_caps = ksz9477_get_caps, 24862306a36Sopenharmony_ci .fdb_dump = ksz9477_fdb_dump, 24962306a36Sopenharmony_ci .fdb_add = ksz9477_fdb_add, 25062306a36Sopenharmony_ci .fdb_del = ksz9477_fdb_del, 25162306a36Sopenharmony_ci .mdb_add = ksz9477_mdb_add, 25262306a36Sopenharmony_ci .mdb_del = ksz9477_mdb_del, 25362306a36Sopenharmony_ci .change_mtu = ksz9477_change_mtu, 25462306a36Sopenharmony_ci .phylink_mac_link_up = ksz9477_phylink_mac_link_up, 25562306a36Sopenharmony_ci .config_cpu_port = ksz9477_config_cpu_port, 25662306a36Sopenharmony_ci .tc_cbs_set_cinc = ksz9477_tc_cbs_set_cinc, 25762306a36Sopenharmony_ci .enable_stp_addr = ksz9477_enable_stp_addr, 25862306a36Sopenharmony_ci .reset = ksz9477_reset_switch, 25962306a36Sopenharmony_ci .init = ksz9477_switch_init, 26062306a36Sopenharmony_ci .exit = ksz9477_switch_exit, 26162306a36Sopenharmony_ci}; 26262306a36Sopenharmony_ci 26362306a36Sopenharmony_cistatic const struct ksz_dev_ops lan937x_dev_ops = { 26462306a36Sopenharmony_ci .setup = lan937x_setup, 26562306a36Sopenharmony_ci .teardown = lan937x_teardown, 26662306a36Sopenharmony_ci .get_port_addr = ksz9477_get_port_addr, 26762306a36Sopenharmony_ci .cfg_port_member = ksz9477_cfg_port_member, 26862306a36Sopenharmony_ci .flush_dyn_mac_table = ksz9477_flush_dyn_mac_table, 26962306a36Sopenharmony_ci .port_setup = lan937x_port_setup, 27062306a36Sopenharmony_ci .set_ageing_time = lan937x_set_ageing_time, 27162306a36Sopenharmony_ci .r_phy = lan937x_r_phy, 27262306a36Sopenharmony_ci .w_phy = lan937x_w_phy, 27362306a36Sopenharmony_ci .r_mib_cnt = ksz9477_r_mib_cnt, 27462306a36Sopenharmony_ci .r_mib_pkt = ksz9477_r_mib_pkt, 27562306a36Sopenharmony_ci .r_mib_stat64 = ksz_r_mib_stats64, 27662306a36Sopenharmony_ci .freeze_mib = ksz9477_freeze_mib, 27762306a36Sopenharmony_ci .port_init_cnt = ksz9477_port_init_cnt, 27862306a36Sopenharmony_ci .vlan_filtering = ksz9477_port_vlan_filtering, 27962306a36Sopenharmony_ci .vlan_add = ksz9477_port_vlan_add, 28062306a36Sopenharmony_ci .vlan_del = ksz9477_port_vlan_del, 28162306a36Sopenharmony_ci .mirror_add = ksz9477_port_mirror_add, 28262306a36Sopenharmony_ci .mirror_del = ksz9477_port_mirror_del, 28362306a36Sopenharmony_ci .get_caps = lan937x_phylink_get_caps, 28462306a36Sopenharmony_ci .setup_rgmii_delay = lan937x_setup_rgmii_delay, 28562306a36Sopenharmony_ci .fdb_dump = ksz9477_fdb_dump, 28662306a36Sopenharmony_ci .fdb_add = ksz9477_fdb_add, 28762306a36Sopenharmony_ci .fdb_del = ksz9477_fdb_del, 28862306a36Sopenharmony_ci .mdb_add = ksz9477_mdb_add, 28962306a36Sopenharmony_ci .mdb_del = ksz9477_mdb_del, 29062306a36Sopenharmony_ci .change_mtu = lan937x_change_mtu, 29162306a36Sopenharmony_ci .phylink_mac_link_up = ksz9477_phylink_mac_link_up, 29262306a36Sopenharmony_ci .config_cpu_port = lan937x_config_cpu_port, 29362306a36Sopenharmony_ci .tc_cbs_set_cinc = lan937x_tc_cbs_set_cinc, 29462306a36Sopenharmony_ci .enable_stp_addr = ksz9477_enable_stp_addr, 29562306a36Sopenharmony_ci .reset = lan937x_reset_switch, 29662306a36Sopenharmony_ci .init = lan937x_switch_init, 29762306a36Sopenharmony_ci .exit = lan937x_switch_exit, 29862306a36Sopenharmony_ci}; 29962306a36Sopenharmony_ci 30062306a36Sopenharmony_cistatic const u16 ksz8795_regs[] = { 30162306a36Sopenharmony_ci [REG_IND_CTRL_0] = 0x6E, 30262306a36Sopenharmony_ci [REG_IND_DATA_8] = 0x70, 30362306a36Sopenharmony_ci [REG_IND_DATA_CHECK] = 0x72, 30462306a36Sopenharmony_ci [REG_IND_DATA_HI] = 0x71, 30562306a36Sopenharmony_ci [REG_IND_DATA_LO] = 0x75, 30662306a36Sopenharmony_ci [REG_IND_MIB_CHECK] = 0x74, 30762306a36Sopenharmony_ci [REG_IND_BYTE] = 0xA0, 30862306a36Sopenharmony_ci [P_FORCE_CTRL] = 0x0C, 30962306a36Sopenharmony_ci [P_LINK_STATUS] = 0x0E, 31062306a36Sopenharmony_ci [P_LOCAL_CTRL] = 0x07, 31162306a36Sopenharmony_ci [P_NEG_RESTART_CTRL] = 0x0D, 31262306a36Sopenharmony_ci [P_REMOTE_STATUS] = 0x08, 31362306a36Sopenharmony_ci [P_SPEED_STATUS] = 0x09, 31462306a36Sopenharmony_ci [S_TAIL_TAG_CTRL] = 0x0C, 31562306a36Sopenharmony_ci [P_STP_CTRL] = 0x02, 31662306a36Sopenharmony_ci [S_START_CTRL] = 0x01, 31762306a36Sopenharmony_ci [S_BROADCAST_CTRL] = 0x06, 31862306a36Sopenharmony_ci [S_MULTICAST_CTRL] = 0x04, 31962306a36Sopenharmony_ci [P_XMII_CTRL_0] = 0x06, 32062306a36Sopenharmony_ci [P_XMII_CTRL_1] = 0x06, 32162306a36Sopenharmony_ci}; 32262306a36Sopenharmony_ci 32362306a36Sopenharmony_cistatic const u32 ksz8795_masks[] = { 32462306a36Sopenharmony_ci [PORT_802_1P_REMAPPING] = BIT(7), 32562306a36Sopenharmony_ci [SW_TAIL_TAG_ENABLE] = BIT(1), 32662306a36Sopenharmony_ci [MIB_COUNTER_OVERFLOW] = BIT(6), 32762306a36Sopenharmony_ci [MIB_COUNTER_VALID] = BIT(5), 32862306a36Sopenharmony_ci [VLAN_TABLE_FID] = GENMASK(6, 0), 32962306a36Sopenharmony_ci [VLAN_TABLE_MEMBERSHIP] = GENMASK(11, 7), 33062306a36Sopenharmony_ci [VLAN_TABLE_VALID] = BIT(12), 33162306a36Sopenharmony_ci [STATIC_MAC_TABLE_VALID] = BIT(21), 33262306a36Sopenharmony_ci [STATIC_MAC_TABLE_USE_FID] = BIT(23), 33362306a36Sopenharmony_ci [STATIC_MAC_TABLE_FID] = GENMASK(30, 24), 33462306a36Sopenharmony_ci [STATIC_MAC_TABLE_OVERRIDE] = BIT(22), 33562306a36Sopenharmony_ci [STATIC_MAC_TABLE_FWD_PORTS] = GENMASK(20, 16), 33662306a36Sopenharmony_ci [DYNAMIC_MAC_TABLE_ENTRIES_H] = GENMASK(6, 0), 33762306a36Sopenharmony_ci [DYNAMIC_MAC_TABLE_MAC_EMPTY] = BIT(7), 33862306a36Sopenharmony_ci [DYNAMIC_MAC_TABLE_NOT_READY] = BIT(7), 33962306a36Sopenharmony_ci [DYNAMIC_MAC_TABLE_ENTRIES] = GENMASK(31, 29), 34062306a36Sopenharmony_ci [DYNAMIC_MAC_TABLE_FID] = GENMASK(22, 16), 34162306a36Sopenharmony_ci [DYNAMIC_MAC_TABLE_SRC_PORT] = GENMASK(26, 24), 34262306a36Sopenharmony_ci [DYNAMIC_MAC_TABLE_TIMESTAMP] = GENMASK(28, 27), 34362306a36Sopenharmony_ci [P_MII_TX_FLOW_CTRL] = BIT(5), 34462306a36Sopenharmony_ci [P_MII_RX_FLOW_CTRL] = BIT(5), 34562306a36Sopenharmony_ci}; 34662306a36Sopenharmony_ci 34762306a36Sopenharmony_cistatic const u8 ksz8795_xmii_ctrl0[] = { 34862306a36Sopenharmony_ci [P_MII_100MBIT] = 0, 34962306a36Sopenharmony_ci [P_MII_10MBIT] = 1, 35062306a36Sopenharmony_ci [P_MII_FULL_DUPLEX] = 0, 35162306a36Sopenharmony_ci [P_MII_HALF_DUPLEX] = 1, 35262306a36Sopenharmony_ci}; 35362306a36Sopenharmony_ci 35462306a36Sopenharmony_cistatic const u8 ksz8795_xmii_ctrl1[] = { 35562306a36Sopenharmony_ci [P_RGMII_SEL] = 3, 35662306a36Sopenharmony_ci [P_GMII_SEL] = 2, 35762306a36Sopenharmony_ci [P_RMII_SEL] = 1, 35862306a36Sopenharmony_ci [P_MII_SEL] = 0, 35962306a36Sopenharmony_ci [P_GMII_1GBIT] = 1, 36062306a36Sopenharmony_ci [P_GMII_NOT_1GBIT] = 0, 36162306a36Sopenharmony_ci}; 36262306a36Sopenharmony_ci 36362306a36Sopenharmony_cistatic const u8 ksz8795_shifts[] = { 36462306a36Sopenharmony_ci [VLAN_TABLE_MEMBERSHIP_S] = 7, 36562306a36Sopenharmony_ci [VLAN_TABLE] = 16, 36662306a36Sopenharmony_ci [STATIC_MAC_FWD_PORTS] = 16, 36762306a36Sopenharmony_ci [STATIC_MAC_FID] = 24, 36862306a36Sopenharmony_ci [DYNAMIC_MAC_ENTRIES_H] = 3, 36962306a36Sopenharmony_ci [DYNAMIC_MAC_ENTRIES] = 29, 37062306a36Sopenharmony_ci [DYNAMIC_MAC_FID] = 16, 37162306a36Sopenharmony_ci [DYNAMIC_MAC_TIMESTAMP] = 27, 37262306a36Sopenharmony_ci [DYNAMIC_MAC_SRC_PORT] = 24, 37362306a36Sopenharmony_ci}; 37462306a36Sopenharmony_ci 37562306a36Sopenharmony_cistatic const u16 ksz8863_regs[] = { 37662306a36Sopenharmony_ci [REG_IND_CTRL_0] = 0x79, 37762306a36Sopenharmony_ci [REG_IND_DATA_8] = 0x7B, 37862306a36Sopenharmony_ci [REG_IND_DATA_CHECK] = 0x7B, 37962306a36Sopenharmony_ci [REG_IND_DATA_HI] = 0x7C, 38062306a36Sopenharmony_ci [REG_IND_DATA_LO] = 0x80, 38162306a36Sopenharmony_ci [REG_IND_MIB_CHECK] = 0x80, 38262306a36Sopenharmony_ci [P_FORCE_CTRL] = 0x0C, 38362306a36Sopenharmony_ci [P_LINK_STATUS] = 0x0E, 38462306a36Sopenharmony_ci [P_LOCAL_CTRL] = 0x0C, 38562306a36Sopenharmony_ci [P_NEG_RESTART_CTRL] = 0x0D, 38662306a36Sopenharmony_ci [P_REMOTE_STATUS] = 0x0E, 38762306a36Sopenharmony_ci [P_SPEED_STATUS] = 0x0F, 38862306a36Sopenharmony_ci [S_TAIL_TAG_CTRL] = 0x03, 38962306a36Sopenharmony_ci [P_STP_CTRL] = 0x02, 39062306a36Sopenharmony_ci [S_START_CTRL] = 0x01, 39162306a36Sopenharmony_ci [S_BROADCAST_CTRL] = 0x06, 39262306a36Sopenharmony_ci [S_MULTICAST_CTRL] = 0x04, 39362306a36Sopenharmony_ci}; 39462306a36Sopenharmony_ci 39562306a36Sopenharmony_cistatic const u32 ksz8863_masks[] = { 39662306a36Sopenharmony_ci [PORT_802_1P_REMAPPING] = BIT(3), 39762306a36Sopenharmony_ci [SW_TAIL_TAG_ENABLE] = BIT(6), 39862306a36Sopenharmony_ci [MIB_COUNTER_OVERFLOW] = BIT(7), 39962306a36Sopenharmony_ci [MIB_COUNTER_VALID] = BIT(6), 40062306a36Sopenharmony_ci [VLAN_TABLE_FID] = GENMASK(15, 12), 40162306a36Sopenharmony_ci [VLAN_TABLE_MEMBERSHIP] = GENMASK(18, 16), 40262306a36Sopenharmony_ci [VLAN_TABLE_VALID] = BIT(19), 40362306a36Sopenharmony_ci [STATIC_MAC_TABLE_VALID] = BIT(19), 40462306a36Sopenharmony_ci [STATIC_MAC_TABLE_USE_FID] = BIT(21), 40562306a36Sopenharmony_ci [STATIC_MAC_TABLE_FID] = GENMASK(25, 22), 40662306a36Sopenharmony_ci [STATIC_MAC_TABLE_OVERRIDE] = BIT(20), 40762306a36Sopenharmony_ci [STATIC_MAC_TABLE_FWD_PORTS] = GENMASK(18, 16), 40862306a36Sopenharmony_ci [DYNAMIC_MAC_TABLE_ENTRIES_H] = GENMASK(1, 0), 40962306a36Sopenharmony_ci [DYNAMIC_MAC_TABLE_MAC_EMPTY] = BIT(2), 41062306a36Sopenharmony_ci [DYNAMIC_MAC_TABLE_NOT_READY] = BIT(7), 41162306a36Sopenharmony_ci [DYNAMIC_MAC_TABLE_ENTRIES] = GENMASK(31, 24), 41262306a36Sopenharmony_ci [DYNAMIC_MAC_TABLE_FID] = GENMASK(19, 16), 41362306a36Sopenharmony_ci [DYNAMIC_MAC_TABLE_SRC_PORT] = GENMASK(21, 20), 41462306a36Sopenharmony_ci [DYNAMIC_MAC_TABLE_TIMESTAMP] = GENMASK(23, 22), 41562306a36Sopenharmony_ci}; 41662306a36Sopenharmony_ci 41762306a36Sopenharmony_cistatic u8 ksz8863_shifts[] = { 41862306a36Sopenharmony_ci [VLAN_TABLE_MEMBERSHIP_S] = 16, 41962306a36Sopenharmony_ci [STATIC_MAC_FWD_PORTS] = 16, 42062306a36Sopenharmony_ci [STATIC_MAC_FID] = 22, 42162306a36Sopenharmony_ci [DYNAMIC_MAC_ENTRIES_H] = 8, 42262306a36Sopenharmony_ci [DYNAMIC_MAC_ENTRIES] = 24, 42362306a36Sopenharmony_ci [DYNAMIC_MAC_FID] = 16, 42462306a36Sopenharmony_ci [DYNAMIC_MAC_TIMESTAMP] = 22, 42562306a36Sopenharmony_ci [DYNAMIC_MAC_SRC_PORT] = 20, 42662306a36Sopenharmony_ci}; 42762306a36Sopenharmony_ci 42862306a36Sopenharmony_cistatic const u16 ksz9477_regs[] = { 42962306a36Sopenharmony_ci [P_STP_CTRL] = 0x0B04, 43062306a36Sopenharmony_ci [S_START_CTRL] = 0x0300, 43162306a36Sopenharmony_ci [S_BROADCAST_CTRL] = 0x0332, 43262306a36Sopenharmony_ci [S_MULTICAST_CTRL] = 0x0331, 43362306a36Sopenharmony_ci [P_XMII_CTRL_0] = 0x0300, 43462306a36Sopenharmony_ci [P_XMII_CTRL_1] = 0x0301, 43562306a36Sopenharmony_ci}; 43662306a36Sopenharmony_ci 43762306a36Sopenharmony_cistatic const u32 ksz9477_masks[] = { 43862306a36Sopenharmony_ci [ALU_STAT_WRITE] = 0, 43962306a36Sopenharmony_ci [ALU_STAT_READ] = 1, 44062306a36Sopenharmony_ci [P_MII_TX_FLOW_CTRL] = BIT(5), 44162306a36Sopenharmony_ci [P_MII_RX_FLOW_CTRL] = BIT(3), 44262306a36Sopenharmony_ci}; 44362306a36Sopenharmony_ci 44462306a36Sopenharmony_cistatic const u8 ksz9477_shifts[] = { 44562306a36Sopenharmony_ci [ALU_STAT_INDEX] = 16, 44662306a36Sopenharmony_ci}; 44762306a36Sopenharmony_ci 44862306a36Sopenharmony_cistatic const u8 ksz9477_xmii_ctrl0[] = { 44962306a36Sopenharmony_ci [P_MII_100MBIT] = 1, 45062306a36Sopenharmony_ci [P_MII_10MBIT] = 0, 45162306a36Sopenharmony_ci [P_MII_FULL_DUPLEX] = 1, 45262306a36Sopenharmony_ci [P_MII_HALF_DUPLEX] = 0, 45362306a36Sopenharmony_ci}; 45462306a36Sopenharmony_ci 45562306a36Sopenharmony_cistatic const u8 ksz9477_xmii_ctrl1[] = { 45662306a36Sopenharmony_ci [P_RGMII_SEL] = 0, 45762306a36Sopenharmony_ci [P_RMII_SEL] = 1, 45862306a36Sopenharmony_ci [P_GMII_SEL] = 2, 45962306a36Sopenharmony_ci [P_MII_SEL] = 3, 46062306a36Sopenharmony_ci [P_GMII_1GBIT] = 0, 46162306a36Sopenharmony_ci [P_GMII_NOT_1GBIT] = 1, 46262306a36Sopenharmony_ci}; 46362306a36Sopenharmony_ci 46462306a36Sopenharmony_cistatic const u32 lan937x_masks[] = { 46562306a36Sopenharmony_ci [ALU_STAT_WRITE] = 1, 46662306a36Sopenharmony_ci [ALU_STAT_READ] = 2, 46762306a36Sopenharmony_ci [P_MII_TX_FLOW_CTRL] = BIT(5), 46862306a36Sopenharmony_ci [P_MII_RX_FLOW_CTRL] = BIT(3), 46962306a36Sopenharmony_ci}; 47062306a36Sopenharmony_ci 47162306a36Sopenharmony_cistatic const u8 lan937x_shifts[] = { 47262306a36Sopenharmony_ci [ALU_STAT_INDEX] = 8, 47362306a36Sopenharmony_ci}; 47462306a36Sopenharmony_ci 47562306a36Sopenharmony_cistatic const struct regmap_range ksz8563_valid_regs[] = { 47662306a36Sopenharmony_ci regmap_reg_range(0x0000, 0x0003), 47762306a36Sopenharmony_ci regmap_reg_range(0x0006, 0x0006), 47862306a36Sopenharmony_ci regmap_reg_range(0x000f, 0x001f), 47962306a36Sopenharmony_ci regmap_reg_range(0x0100, 0x0100), 48062306a36Sopenharmony_ci regmap_reg_range(0x0104, 0x0107), 48162306a36Sopenharmony_ci regmap_reg_range(0x010d, 0x010d), 48262306a36Sopenharmony_ci regmap_reg_range(0x0110, 0x0113), 48362306a36Sopenharmony_ci regmap_reg_range(0x0120, 0x012b), 48462306a36Sopenharmony_ci regmap_reg_range(0x0201, 0x0201), 48562306a36Sopenharmony_ci regmap_reg_range(0x0210, 0x0213), 48662306a36Sopenharmony_ci regmap_reg_range(0x0300, 0x0300), 48762306a36Sopenharmony_ci regmap_reg_range(0x0302, 0x031b), 48862306a36Sopenharmony_ci regmap_reg_range(0x0320, 0x032b), 48962306a36Sopenharmony_ci regmap_reg_range(0x0330, 0x0336), 49062306a36Sopenharmony_ci regmap_reg_range(0x0338, 0x033e), 49162306a36Sopenharmony_ci regmap_reg_range(0x0340, 0x035f), 49262306a36Sopenharmony_ci regmap_reg_range(0x0370, 0x0370), 49362306a36Sopenharmony_ci regmap_reg_range(0x0378, 0x0378), 49462306a36Sopenharmony_ci regmap_reg_range(0x037c, 0x037d), 49562306a36Sopenharmony_ci regmap_reg_range(0x0390, 0x0393), 49662306a36Sopenharmony_ci regmap_reg_range(0x0400, 0x040e), 49762306a36Sopenharmony_ci regmap_reg_range(0x0410, 0x042f), 49862306a36Sopenharmony_ci regmap_reg_range(0x0500, 0x0519), 49962306a36Sopenharmony_ci regmap_reg_range(0x0520, 0x054b), 50062306a36Sopenharmony_ci regmap_reg_range(0x0550, 0x05b3), 50162306a36Sopenharmony_ci 50262306a36Sopenharmony_ci /* port 1 */ 50362306a36Sopenharmony_ci regmap_reg_range(0x1000, 0x1001), 50462306a36Sopenharmony_ci regmap_reg_range(0x1004, 0x100b), 50562306a36Sopenharmony_ci regmap_reg_range(0x1013, 0x1013), 50662306a36Sopenharmony_ci regmap_reg_range(0x1017, 0x1017), 50762306a36Sopenharmony_ci regmap_reg_range(0x101b, 0x101b), 50862306a36Sopenharmony_ci regmap_reg_range(0x101f, 0x1021), 50962306a36Sopenharmony_ci regmap_reg_range(0x1030, 0x1030), 51062306a36Sopenharmony_ci regmap_reg_range(0x1100, 0x1111), 51162306a36Sopenharmony_ci regmap_reg_range(0x111a, 0x111d), 51262306a36Sopenharmony_ci regmap_reg_range(0x1122, 0x1127), 51362306a36Sopenharmony_ci regmap_reg_range(0x112a, 0x112b), 51462306a36Sopenharmony_ci regmap_reg_range(0x1136, 0x1139), 51562306a36Sopenharmony_ci regmap_reg_range(0x113e, 0x113f), 51662306a36Sopenharmony_ci regmap_reg_range(0x1400, 0x1401), 51762306a36Sopenharmony_ci regmap_reg_range(0x1403, 0x1403), 51862306a36Sopenharmony_ci regmap_reg_range(0x1410, 0x1417), 51962306a36Sopenharmony_ci regmap_reg_range(0x1420, 0x1423), 52062306a36Sopenharmony_ci regmap_reg_range(0x1500, 0x1507), 52162306a36Sopenharmony_ci regmap_reg_range(0x1600, 0x1612), 52262306a36Sopenharmony_ci regmap_reg_range(0x1800, 0x180f), 52362306a36Sopenharmony_ci regmap_reg_range(0x1900, 0x1907), 52462306a36Sopenharmony_ci regmap_reg_range(0x1914, 0x191b), 52562306a36Sopenharmony_ci regmap_reg_range(0x1a00, 0x1a03), 52662306a36Sopenharmony_ci regmap_reg_range(0x1a04, 0x1a08), 52762306a36Sopenharmony_ci regmap_reg_range(0x1b00, 0x1b01), 52862306a36Sopenharmony_ci regmap_reg_range(0x1b04, 0x1b04), 52962306a36Sopenharmony_ci regmap_reg_range(0x1c00, 0x1c05), 53062306a36Sopenharmony_ci regmap_reg_range(0x1c08, 0x1c1b), 53162306a36Sopenharmony_ci 53262306a36Sopenharmony_ci /* port 2 */ 53362306a36Sopenharmony_ci regmap_reg_range(0x2000, 0x2001), 53462306a36Sopenharmony_ci regmap_reg_range(0x2004, 0x200b), 53562306a36Sopenharmony_ci regmap_reg_range(0x2013, 0x2013), 53662306a36Sopenharmony_ci regmap_reg_range(0x2017, 0x2017), 53762306a36Sopenharmony_ci regmap_reg_range(0x201b, 0x201b), 53862306a36Sopenharmony_ci regmap_reg_range(0x201f, 0x2021), 53962306a36Sopenharmony_ci regmap_reg_range(0x2030, 0x2030), 54062306a36Sopenharmony_ci regmap_reg_range(0x2100, 0x2111), 54162306a36Sopenharmony_ci regmap_reg_range(0x211a, 0x211d), 54262306a36Sopenharmony_ci regmap_reg_range(0x2122, 0x2127), 54362306a36Sopenharmony_ci regmap_reg_range(0x212a, 0x212b), 54462306a36Sopenharmony_ci regmap_reg_range(0x2136, 0x2139), 54562306a36Sopenharmony_ci regmap_reg_range(0x213e, 0x213f), 54662306a36Sopenharmony_ci regmap_reg_range(0x2400, 0x2401), 54762306a36Sopenharmony_ci regmap_reg_range(0x2403, 0x2403), 54862306a36Sopenharmony_ci regmap_reg_range(0x2410, 0x2417), 54962306a36Sopenharmony_ci regmap_reg_range(0x2420, 0x2423), 55062306a36Sopenharmony_ci regmap_reg_range(0x2500, 0x2507), 55162306a36Sopenharmony_ci regmap_reg_range(0x2600, 0x2612), 55262306a36Sopenharmony_ci regmap_reg_range(0x2800, 0x280f), 55362306a36Sopenharmony_ci regmap_reg_range(0x2900, 0x2907), 55462306a36Sopenharmony_ci regmap_reg_range(0x2914, 0x291b), 55562306a36Sopenharmony_ci regmap_reg_range(0x2a00, 0x2a03), 55662306a36Sopenharmony_ci regmap_reg_range(0x2a04, 0x2a08), 55762306a36Sopenharmony_ci regmap_reg_range(0x2b00, 0x2b01), 55862306a36Sopenharmony_ci regmap_reg_range(0x2b04, 0x2b04), 55962306a36Sopenharmony_ci regmap_reg_range(0x2c00, 0x2c05), 56062306a36Sopenharmony_ci regmap_reg_range(0x2c08, 0x2c1b), 56162306a36Sopenharmony_ci 56262306a36Sopenharmony_ci /* port 3 */ 56362306a36Sopenharmony_ci regmap_reg_range(0x3000, 0x3001), 56462306a36Sopenharmony_ci regmap_reg_range(0x3004, 0x300b), 56562306a36Sopenharmony_ci regmap_reg_range(0x3013, 0x3013), 56662306a36Sopenharmony_ci regmap_reg_range(0x3017, 0x3017), 56762306a36Sopenharmony_ci regmap_reg_range(0x301b, 0x301b), 56862306a36Sopenharmony_ci regmap_reg_range(0x301f, 0x3021), 56962306a36Sopenharmony_ci regmap_reg_range(0x3030, 0x3030), 57062306a36Sopenharmony_ci regmap_reg_range(0x3300, 0x3301), 57162306a36Sopenharmony_ci regmap_reg_range(0x3303, 0x3303), 57262306a36Sopenharmony_ci regmap_reg_range(0x3400, 0x3401), 57362306a36Sopenharmony_ci regmap_reg_range(0x3403, 0x3403), 57462306a36Sopenharmony_ci regmap_reg_range(0x3410, 0x3417), 57562306a36Sopenharmony_ci regmap_reg_range(0x3420, 0x3423), 57662306a36Sopenharmony_ci regmap_reg_range(0x3500, 0x3507), 57762306a36Sopenharmony_ci regmap_reg_range(0x3600, 0x3612), 57862306a36Sopenharmony_ci regmap_reg_range(0x3800, 0x380f), 57962306a36Sopenharmony_ci regmap_reg_range(0x3900, 0x3907), 58062306a36Sopenharmony_ci regmap_reg_range(0x3914, 0x391b), 58162306a36Sopenharmony_ci regmap_reg_range(0x3a00, 0x3a03), 58262306a36Sopenharmony_ci regmap_reg_range(0x3a04, 0x3a08), 58362306a36Sopenharmony_ci regmap_reg_range(0x3b00, 0x3b01), 58462306a36Sopenharmony_ci regmap_reg_range(0x3b04, 0x3b04), 58562306a36Sopenharmony_ci regmap_reg_range(0x3c00, 0x3c05), 58662306a36Sopenharmony_ci regmap_reg_range(0x3c08, 0x3c1b), 58762306a36Sopenharmony_ci}; 58862306a36Sopenharmony_ci 58962306a36Sopenharmony_cistatic const struct regmap_access_table ksz8563_register_set = { 59062306a36Sopenharmony_ci .yes_ranges = ksz8563_valid_regs, 59162306a36Sopenharmony_ci .n_yes_ranges = ARRAY_SIZE(ksz8563_valid_regs), 59262306a36Sopenharmony_ci}; 59362306a36Sopenharmony_ci 59462306a36Sopenharmony_cistatic const struct regmap_range ksz9477_valid_regs[] = { 59562306a36Sopenharmony_ci regmap_reg_range(0x0000, 0x0003), 59662306a36Sopenharmony_ci regmap_reg_range(0x0006, 0x0006), 59762306a36Sopenharmony_ci regmap_reg_range(0x0010, 0x001f), 59862306a36Sopenharmony_ci regmap_reg_range(0x0100, 0x0100), 59962306a36Sopenharmony_ci regmap_reg_range(0x0103, 0x0107), 60062306a36Sopenharmony_ci regmap_reg_range(0x010d, 0x010d), 60162306a36Sopenharmony_ci regmap_reg_range(0x0110, 0x0113), 60262306a36Sopenharmony_ci regmap_reg_range(0x0120, 0x012b), 60362306a36Sopenharmony_ci regmap_reg_range(0x0201, 0x0201), 60462306a36Sopenharmony_ci regmap_reg_range(0x0210, 0x0213), 60562306a36Sopenharmony_ci regmap_reg_range(0x0300, 0x0300), 60662306a36Sopenharmony_ci regmap_reg_range(0x0302, 0x031b), 60762306a36Sopenharmony_ci regmap_reg_range(0x0320, 0x032b), 60862306a36Sopenharmony_ci regmap_reg_range(0x0330, 0x0336), 60962306a36Sopenharmony_ci regmap_reg_range(0x0338, 0x033b), 61062306a36Sopenharmony_ci regmap_reg_range(0x033e, 0x033e), 61162306a36Sopenharmony_ci regmap_reg_range(0x0340, 0x035f), 61262306a36Sopenharmony_ci regmap_reg_range(0x0370, 0x0370), 61362306a36Sopenharmony_ci regmap_reg_range(0x0378, 0x0378), 61462306a36Sopenharmony_ci regmap_reg_range(0x037c, 0x037d), 61562306a36Sopenharmony_ci regmap_reg_range(0x0390, 0x0393), 61662306a36Sopenharmony_ci regmap_reg_range(0x0400, 0x040e), 61762306a36Sopenharmony_ci regmap_reg_range(0x0410, 0x042f), 61862306a36Sopenharmony_ci regmap_reg_range(0x0444, 0x044b), 61962306a36Sopenharmony_ci regmap_reg_range(0x0450, 0x046f), 62062306a36Sopenharmony_ci regmap_reg_range(0x0500, 0x0519), 62162306a36Sopenharmony_ci regmap_reg_range(0x0520, 0x054b), 62262306a36Sopenharmony_ci regmap_reg_range(0x0550, 0x05b3), 62362306a36Sopenharmony_ci regmap_reg_range(0x0604, 0x060b), 62462306a36Sopenharmony_ci regmap_reg_range(0x0610, 0x0612), 62562306a36Sopenharmony_ci regmap_reg_range(0x0614, 0x062c), 62662306a36Sopenharmony_ci regmap_reg_range(0x0640, 0x0645), 62762306a36Sopenharmony_ci regmap_reg_range(0x0648, 0x064d), 62862306a36Sopenharmony_ci 62962306a36Sopenharmony_ci /* port 1 */ 63062306a36Sopenharmony_ci regmap_reg_range(0x1000, 0x1001), 63162306a36Sopenharmony_ci regmap_reg_range(0x1013, 0x1013), 63262306a36Sopenharmony_ci regmap_reg_range(0x1017, 0x1017), 63362306a36Sopenharmony_ci regmap_reg_range(0x101b, 0x101b), 63462306a36Sopenharmony_ci regmap_reg_range(0x101f, 0x1020), 63562306a36Sopenharmony_ci regmap_reg_range(0x1030, 0x1030), 63662306a36Sopenharmony_ci regmap_reg_range(0x1100, 0x1115), 63762306a36Sopenharmony_ci regmap_reg_range(0x111a, 0x111f), 63862306a36Sopenharmony_ci regmap_reg_range(0x1120, 0x112b), 63962306a36Sopenharmony_ci regmap_reg_range(0x1134, 0x113b), 64062306a36Sopenharmony_ci regmap_reg_range(0x113c, 0x113f), 64162306a36Sopenharmony_ci regmap_reg_range(0x1400, 0x1401), 64262306a36Sopenharmony_ci regmap_reg_range(0x1403, 0x1403), 64362306a36Sopenharmony_ci regmap_reg_range(0x1410, 0x1417), 64462306a36Sopenharmony_ci regmap_reg_range(0x1420, 0x1423), 64562306a36Sopenharmony_ci regmap_reg_range(0x1500, 0x1507), 64662306a36Sopenharmony_ci regmap_reg_range(0x1600, 0x1613), 64762306a36Sopenharmony_ci regmap_reg_range(0x1800, 0x180f), 64862306a36Sopenharmony_ci regmap_reg_range(0x1820, 0x1827), 64962306a36Sopenharmony_ci regmap_reg_range(0x1830, 0x1837), 65062306a36Sopenharmony_ci regmap_reg_range(0x1840, 0x184b), 65162306a36Sopenharmony_ci regmap_reg_range(0x1900, 0x1907), 65262306a36Sopenharmony_ci regmap_reg_range(0x1914, 0x191b), 65362306a36Sopenharmony_ci regmap_reg_range(0x1920, 0x1920), 65462306a36Sopenharmony_ci regmap_reg_range(0x1923, 0x1927), 65562306a36Sopenharmony_ci regmap_reg_range(0x1a00, 0x1a03), 65662306a36Sopenharmony_ci regmap_reg_range(0x1a04, 0x1a07), 65762306a36Sopenharmony_ci regmap_reg_range(0x1b00, 0x1b01), 65862306a36Sopenharmony_ci regmap_reg_range(0x1b04, 0x1b04), 65962306a36Sopenharmony_ci regmap_reg_range(0x1c00, 0x1c05), 66062306a36Sopenharmony_ci regmap_reg_range(0x1c08, 0x1c1b), 66162306a36Sopenharmony_ci 66262306a36Sopenharmony_ci /* port 2 */ 66362306a36Sopenharmony_ci regmap_reg_range(0x2000, 0x2001), 66462306a36Sopenharmony_ci regmap_reg_range(0x2013, 0x2013), 66562306a36Sopenharmony_ci regmap_reg_range(0x2017, 0x2017), 66662306a36Sopenharmony_ci regmap_reg_range(0x201b, 0x201b), 66762306a36Sopenharmony_ci regmap_reg_range(0x201f, 0x2020), 66862306a36Sopenharmony_ci regmap_reg_range(0x2030, 0x2030), 66962306a36Sopenharmony_ci regmap_reg_range(0x2100, 0x2115), 67062306a36Sopenharmony_ci regmap_reg_range(0x211a, 0x211f), 67162306a36Sopenharmony_ci regmap_reg_range(0x2120, 0x212b), 67262306a36Sopenharmony_ci regmap_reg_range(0x2134, 0x213b), 67362306a36Sopenharmony_ci regmap_reg_range(0x213c, 0x213f), 67462306a36Sopenharmony_ci regmap_reg_range(0x2400, 0x2401), 67562306a36Sopenharmony_ci regmap_reg_range(0x2403, 0x2403), 67662306a36Sopenharmony_ci regmap_reg_range(0x2410, 0x2417), 67762306a36Sopenharmony_ci regmap_reg_range(0x2420, 0x2423), 67862306a36Sopenharmony_ci regmap_reg_range(0x2500, 0x2507), 67962306a36Sopenharmony_ci regmap_reg_range(0x2600, 0x2613), 68062306a36Sopenharmony_ci regmap_reg_range(0x2800, 0x280f), 68162306a36Sopenharmony_ci regmap_reg_range(0x2820, 0x2827), 68262306a36Sopenharmony_ci regmap_reg_range(0x2830, 0x2837), 68362306a36Sopenharmony_ci regmap_reg_range(0x2840, 0x284b), 68462306a36Sopenharmony_ci regmap_reg_range(0x2900, 0x2907), 68562306a36Sopenharmony_ci regmap_reg_range(0x2914, 0x291b), 68662306a36Sopenharmony_ci regmap_reg_range(0x2920, 0x2920), 68762306a36Sopenharmony_ci regmap_reg_range(0x2923, 0x2927), 68862306a36Sopenharmony_ci regmap_reg_range(0x2a00, 0x2a03), 68962306a36Sopenharmony_ci regmap_reg_range(0x2a04, 0x2a07), 69062306a36Sopenharmony_ci regmap_reg_range(0x2b00, 0x2b01), 69162306a36Sopenharmony_ci regmap_reg_range(0x2b04, 0x2b04), 69262306a36Sopenharmony_ci regmap_reg_range(0x2c00, 0x2c05), 69362306a36Sopenharmony_ci regmap_reg_range(0x2c08, 0x2c1b), 69462306a36Sopenharmony_ci 69562306a36Sopenharmony_ci /* port 3 */ 69662306a36Sopenharmony_ci regmap_reg_range(0x3000, 0x3001), 69762306a36Sopenharmony_ci regmap_reg_range(0x3013, 0x3013), 69862306a36Sopenharmony_ci regmap_reg_range(0x3017, 0x3017), 69962306a36Sopenharmony_ci regmap_reg_range(0x301b, 0x301b), 70062306a36Sopenharmony_ci regmap_reg_range(0x301f, 0x3020), 70162306a36Sopenharmony_ci regmap_reg_range(0x3030, 0x3030), 70262306a36Sopenharmony_ci regmap_reg_range(0x3100, 0x3115), 70362306a36Sopenharmony_ci regmap_reg_range(0x311a, 0x311f), 70462306a36Sopenharmony_ci regmap_reg_range(0x3120, 0x312b), 70562306a36Sopenharmony_ci regmap_reg_range(0x3134, 0x313b), 70662306a36Sopenharmony_ci regmap_reg_range(0x313c, 0x313f), 70762306a36Sopenharmony_ci regmap_reg_range(0x3400, 0x3401), 70862306a36Sopenharmony_ci regmap_reg_range(0x3403, 0x3403), 70962306a36Sopenharmony_ci regmap_reg_range(0x3410, 0x3417), 71062306a36Sopenharmony_ci regmap_reg_range(0x3420, 0x3423), 71162306a36Sopenharmony_ci regmap_reg_range(0x3500, 0x3507), 71262306a36Sopenharmony_ci regmap_reg_range(0x3600, 0x3613), 71362306a36Sopenharmony_ci regmap_reg_range(0x3800, 0x380f), 71462306a36Sopenharmony_ci regmap_reg_range(0x3820, 0x3827), 71562306a36Sopenharmony_ci regmap_reg_range(0x3830, 0x3837), 71662306a36Sopenharmony_ci regmap_reg_range(0x3840, 0x384b), 71762306a36Sopenharmony_ci regmap_reg_range(0x3900, 0x3907), 71862306a36Sopenharmony_ci regmap_reg_range(0x3914, 0x391b), 71962306a36Sopenharmony_ci regmap_reg_range(0x3920, 0x3920), 72062306a36Sopenharmony_ci regmap_reg_range(0x3923, 0x3927), 72162306a36Sopenharmony_ci regmap_reg_range(0x3a00, 0x3a03), 72262306a36Sopenharmony_ci regmap_reg_range(0x3a04, 0x3a07), 72362306a36Sopenharmony_ci regmap_reg_range(0x3b00, 0x3b01), 72462306a36Sopenharmony_ci regmap_reg_range(0x3b04, 0x3b04), 72562306a36Sopenharmony_ci regmap_reg_range(0x3c00, 0x3c05), 72662306a36Sopenharmony_ci regmap_reg_range(0x3c08, 0x3c1b), 72762306a36Sopenharmony_ci 72862306a36Sopenharmony_ci /* port 4 */ 72962306a36Sopenharmony_ci regmap_reg_range(0x4000, 0x4001), 73062306a36Sopenharmony_ci regmap_reg_range(0x4013, 0x4013), 73162306a36Sopenharmony_ci regmap_reg_range(0x4017, 0x4017), 73262306a36Sopenharmony_ci regmap_reg_range(0x401b, 0x401b), 73362306a36Sopenharmony_ci regmap_reg_range(0x401f, 0x4020), 73462306a36Sopenharmony_ci regmap_reg_range(0x4030, 0x4030), 73562306a36Sopenharmony_ci regmap_reg_range(0x4100, 0x4115), 73662306a36Sopenharmony_ci regmap_reg_range(0x411a, 0x411f), 73762306a36Sopenharmony_ci regmap_reg_range(0x4120, 0x412b), 73862306a36Sopenharmony_ci regmap_reg_range(0x4134, 0x413b), 73962306a36Sopenharmony_ci regmap_reg_range(0x413c, 0x413f), 74062306a36Sopenharmony_ci regmap_reg_range(0x4400, 0x4401), 74162306a36Sopenharmony_ci regmap_reg_range(0x4403, 0x4403), 74262306a36Sopenharmony_ci regmap_reg_range(0x4410, 0x4417), 74362306a36Sopenharmony_ci regmap_reg_range(0x4420, 0x4423), 74462306a36Sopenharmony_ci regmap_reg_range(0x4500, 0x4507), 74562306a36Sopenharmony_ci regmap_reg_range(0x4600, 0x4613), 74662306a36Sopenharmony_ci regmap_reg_range(0x4800, 0x480f), 74762306a36Sopenharmony_ci regmap_reg_range(0x4820, 0x4827), 74862306a36Sopenharmony_ci regmap_reg_range(0x4830, 0x4837), 74962306a36Sopenharmony_ci regmap_reg_range(0x4840, 0x484b), 75062306a36Sopenharmony_ci regmap_reg_range(0x4900, 0x4907), 75162306a36Sopenharmony_ci regmap_reg_range(0x4914, 0x491b), 75262306a36Sopenharmony_ci regmap_reg_range(0x4920, 0x4920), 75362306a36Sopenharmony_ci regmap_reg_range(0x4923, 0x4927), 75462306a36Sopenharmony_ci regmap_reg_range(0x4a00, 0x4a03), 75562306a36Sopenharmony_ci regmap_reg_range(0x4a04, 0x4a07), 75662306a36Sopenharmony_ci regmap_reg_range(0x4b00, 0x4b01), 75762306a36Sopenharmony_ci regmap_reg_range(0x4b04, 0x4b04), 75862306a36Sopenharmony_ci regmap_reg_range(0x4c00, 0x4c05), 75962306a36Sopenharmony_ci regmap_reg_range(0x4c08, 0x4c1b), 76062306a36Sopenharmony_ci 76162306a36Sopenharmony_ci /* port 5 */ 76262306a36Sopenharmony_ci regmap_reg_range(0x5000, 0x5001), 76362306a36Sopenharmony_ci regmap_reg_range(0x5013, 0x5013), 76462306a36Sopenharmony_ci regmap_reg_range(0x5017, 0x5017), 76562306a36Sopenharmony_ci regmap_reg_range(0x501b, 0x501b), 76662306a36Sopenharmony_ci regmap_reg_range(0x501f, 0x5020), 76762306a36Sopenharmony_ci regmap_reg_range(0x5030, 0x5030), 76862306a36Sopenharmony_ci regmap_reg_range(0x5100, 0x5115), 76962306a36Sopenharmony_ci regmap_reg_range(0x511a, 0x511f), 77062306a36Sopenharmony_ci regmap_reg_range(0x5120, 0x512b), 77162306a36Sopenharmony_ci regmap_reg_range(0x5134, 0x513b), 77262306a36Sopenharmony_ci regmap_reg_range(0x513c, 0x513f), 77362306a36Sopenharmony_ci regmap_reg_range(0x5400, 0x5401), 77462306a36Sopenharmony_ci regmap_reg_range(0x5403, 0x5403), 77562306a36Sopenharmony_ci regmap_reg_range(0x5410, 0x5417), 77662306a36Sopenharmony_ci regmap_reg_range(0x5420, 0x5423), 77762306a36Sopenharmony_ci regmap_reg_range(0x5500, 0x5507), 77862306a36Sopenharmony_ci regmap_reg_range(0x5600, 0x5613), 77962306a36Sopenharmony_ci regmap_reg_range(0x5800, 0x580f), 78062306a36Sopenharmony_ci regmap_reg_range(0x5820, 0x5827), 78162306a36Sopenharmony_ci regmap_reg_range(0x5830, 0x5837), 78262306a36Sopenharmony_ci regmap_reg_range(0x5840, 0x584b), 78362306a36Sopenharmony_ci regmap_reg_range(0x5900, 0x5907), 78462306a36Sopenharmony_ci regmap_reg_range(0x5914, 0x591b), 78562306a36Sopenharmony_ci regmap_reg_range(0x5920, 0x5920), 78662306a36Sopenharmony_ci regmap_reg_range(0x5923, 0x5927), 78762306a36Sopenharmony_ci regmap_reg_range(0x5a00, 0x5a03), 78862306a36Sopenharmony_ci regmap_reg_range(0x5a04, 0x5a07), 78962306a36Sopenharmony_ci regmap_reg_range(0x5b00, 0x5b01), 79062306a36Sopenharmony_ci regmap_reg_range(0x5b04, 0x5b04), 79162306a36Sopenharmony_ci regmap_reg_range(0x5c00, 0x5c05), 79262306a36Sopenharmony_ci regmap_reg_range(0x5c08, 0x5c1b), 79362306a36Sopenharmony_ci 79462306a36Sopenharmony_ci /* port 6 */ 79562306a36Sopenharmony_ci regmap_reg_range(0x6000, 0x6001), 79662306a36Sopenharmony_ci regmap_reg_range(0x6013, 0x6013), 79762306a36Sopenharmony_ci regmap_reg_range(0x6017, 0x6017), 79862306a36Sopenharmony_ci regmap_reg_range(0x601b, 0x601b), 79962306a36Sopenharmony_ci regmap_reg_range(0x601f, 0x6020), 80062306a36Sopenharmony_ci regmap_reg_range(0x6030, 0x6030), 80162306a36Sopenharmony_ci regmap_reg_range(0x6300, 0x6301), 80262306a36Sopenharmony_ci regmap_reg_range(0x6400, 0x6401), 80362306a36Sopenharmony_ci regmap_reg_range(0x6403, 0x6403), 80462306a36Sopenharmony_ci regmap_reg_range(0x6410, 0x6417), 80562306a36Sopenharmony_ci regmap_reg_range(0x6420, 0x6423), 80662306a36Sopenharmony_ci regmap_reg_range(0x6500, 0x6507), 80762306a36Sopenharmony_ci regmap_reg_range(0x6600, 0x6613), 80862306a36Sopenharmony_ci regmap_reg_range(0x6800, 0x680f), 80962306a36Sopenharmony_ci regmap_reg_range(0x6820, 0x6827), 81062306a36Sopenharmony_ci regmap_reg_range(0x6830, 0x6837), 81162306a36Sopenharmony_ci regmap_reg_range(0x6840, 0x684b), 81262306a36Sopenharmony_ci regmap_reg_range(0x6900, 0x6907), 81362306a36Sopenharmony_ci regmap_reg_range(0x6914, 0x691b), 81462306a36Sopenharmony_ci regmap_reg_range(0x6920, 0x6920), 81562306a36Sopenharmony_ci regmap_reg_range(0x6923, 0x6927), 81662306a36Sopenharmony_ci regmap_reg_range(0x6a00, 0x6a03), 81762306a36Sopenharmony_ci regmap_reg_range(0x6a04, 0x6a07), 81862306a36Sopenharmony_ci regmap_reg_range(0x6b00, 0x6b01), 81962306a36Sopenharmony_ci regmap_reg_range(0x6b04, 0x6b04), 82062306a36Sopenharmony_ci regmap_reg_range(0x6c00, 0x6c05), 82162306a36Sopenharmony_ci regmap_reg_range(0x6c08, 0x6c1b), 82262306a36Sopenharmony_ci 82362306a36Sopenharmony_ci /* port 7 */ 82462306a36Sopenharmony_ci regmap_reg_range(0x7000, 0x7001), 82562306a36Sopenharmony_ci regmap_reg_range(0x7013, 0x7013), 82662306a36Sopenharmony_ci regmap_reg_range(0x7017, 0x7017), 82762306a36Sopenharmony_ci regmap_reg_range(0x701b, 0x701b), 82862306a36Sopenharmony_ci regmap_reg_range(0x701f, 0x7020), 82962306a36Sopenharmony_ci regmap_reg_range(0x7030, 0x7030), 83062306a36Sopenharmony_ci regmap_reg_range(0x7200, 0x7203), 83162306a36Sopenharmony_ci regmap_reg_range(0x7206, 0x7207), 83262306a36Sopenharmony_ci regmap_reg_range(0x7300, 0x7301), 83362306a36Sopenharmony_ci regmap_reg_range(0x7400, 0x7401), 83462306a36Sopenharmony_ci regmap_reg_range(0x7403, 0x7403), 83562306a36Sopenharmony_ci regmap_reg_range(0x7410, 0x7417), 83662306a36Sopenharmony_ci regmap_reg_range(0x7420, 0x7423), 83762306a36Sopenharmony_ci regmap_reg_range(0x7500, 0x7507), 83862306a36Sopenharmony_ci regmap_reg_range(0x7600, 0x7613), 83962306a36Sopenharmony_ci regmap_reg_range(0x7800, 0x780f), 84062306a36Sopenharmony_ci regmap_reg_range(0x7820, 0x7827), 84162306a36Sopenharmony_ci regmap_reg_range(0x7830, 0x7837), 84262306a36Sopenharmony_ci regmap_reg_range(0x7840, 0x784b), 84362306a36Sopenharmony_ci regmap_reg_range(0x7900, 0x7907), 84462306a36Sopenharmony_ci regmap_reg_range(0x7914, 0x791b), 84562306a36Sopenharmony_ci regmap_reg_range(0x7920, 0x7920), 84662306a36Sopenharmony_ci regmap_reg_range(0x7923, 0x7927), 84762306a36Sopenharmony_ci regmap_reg_range(0x7a00, 0x7a03), 84862306a36Sopenharmony_ci regmap_reg_range(0x7a04, 0x7a07), 84962306a36Sopenharmony_ci regmap_reg_range(0x7b00, 0x7b01), 85062306a36Sopenharmony_ci regmap_reg_range(0x7b04, 0x7b04), 85162306a36Sopenharmony_ci regmap_reg_range(0x7c00, 0x7c05), 85262306a36Sopenharmony_ci regmap_reg_range(0x7c08, 0x7c1b), 85362306a36Sopenharmony_ci}; 85462306a36Sopenharmony_ci 85562306a36Sopenharmony_cistatic const struct regmap_access_table ksz9477_register_set = { 85662306a36Sopenharmony_ci .yes_ranges = ksz9477_valid_regs, 85762306a36Sopenharmony_ci .n_yes_ranges = ARRAY_SIZE(ksz9477_valid_regs), 85862306a36Sopenharmony_ci}; 85962306a36Sopenharmony_ci 86062306a36Sopenharmony_cistatic const struct regmap_range ksz9896_valid_regs[] = { 86162306a36Sopenharmony_ci regmap_reg_range(0x0000, 0x0003), 86262306a36Sopenharmony_ci regmap_reg_range(0x0006, 0x0006), 86362306a36Sopenharmony_ci regmap_reg_range(0x0010, 0x001f), 86462306a36Sopenharmony_ci regmap_reg_range(0x0100, 0x0100), 86562306a36Sopenharmony_ci regmap_reg_range(0x0103, 0x0107), 86662306a36Sopenharmony_ci regmap_reg_range(0x010d, 0x010d), 86762306a36Sopenharmony_ci regmap_reg_range(0x0110, 0x0113), 86862306a36Sopenharmony_ci regmap_reg_range(0x0120, 0x0127), 86962306a36Sopenharmony_ci regmap_reg_range(0x0201, 0x0201), 87062306a36Sopenharmony_ci regmap_reg_range(0x0210, 0x0213), 87162306a36Sopenharmony_ci regmap_reg_range(0x0300, 0x0300), 87262306a36Sopenharmony_ci regmap_reg_range(0x0302, 0x030b), 87362306a36Sopenharmony_ci regmap_reg_range(0x0310, 0x031b), 87462306a36Sopenharmony_ci regmap_reg_range(0x0320, 0x032b), 87562306a36Sopenharmony_ci regmap_reg_range(0x0330, 0x0336), 87662306a36Sopenharmony_ci regmap_reg_range(0x0338, 0x033b), 87762306a36Sopenharmony_ci regmap_reg_range(0x033e, 0x033e), 87862306a36Sopenharmony_ci regmap_reg_range(0x0340, 0x035f), 87962306a36Sopenharmony_ci regmap_reg_range(0x0370, 0x0370), 88062306a36Sopenharmony_ci regmap_reg_range(0x0378, 0x0378), 88162306a36Sopenharmony_ci regmap_reg_range(0x037c, 0x037d), 88262306a36Sopenharmony_ci regmap_reg_range(0x0390, 0x0393), 88362306a36Sopenharmony_ci regmap_reg_range(0x0400, 0x040e), 88462306a36Sopenharmony_ci regmap_reg_range(0x0410, 0x042f), 88562306a36Sopenharmony_ci 88662306a36Sopenharmony_ci /* port 1 */ 88762306a36Sopenharmony_ci regmap_reg_range(0x1000, 0x1001), 88862306a36Sopenharmony_ci regmap_reg_range(0x1013, 0x1013), 88962306a36Sopenharmony_ci regmap_reg_range(0x1017, 0x1017), 89062306a36Sopenharmony_ci regmap_reg_range(0x101b, 0x101b), 89162306a36Sopenharmony_ci regmap_reg_range(0x101f, 0x1020), 89262306a36Sopenharmony_ci regmap_reg_range(0x1030, 0x1030), 89362306a36Sopenharmony_ci regmap_reg_range(0x1100, 0x1115), 89462306a36Sopenharmony_ci regmap_reg_range(0x111a, 0x111f), 89562306a36Sopenharmony_ci regmap_reg_range(0x1122, 0x1127), 89662306a36Sopenharmony_ci regmap_reg_range(0x112a, 0x112b), 89762306a36Sopenharmony_ci regmap_reg_range(0x1136, 0x1139), 89862306a36Sopenharmony_ci regmap_reg_range(0x113e, 0x113f), 89962306a36Sopenharmony_ci regmap_reg_range(0x1400, 0x1401), 90062306a36Sopenharmony_ci regmap_reg_range(0x1403, 0x1403), 90162306a36Sopenharmony_ci regmap_reg_range(0x1410, 0x1417), 90262306a36Sopenharmony_ci regmap_reg_range(0x1420, 0x1423), 90362306a36Sopenharmony_ci regmap_reg_range(0x1500, 0x1507), 90462306a36Sopenharmony_ci regmap_reg_range(0x1600, 0x1612), 90562306a36Sopenharmony_ci regmap_reg_range(0x1800, 0x180f), 90662306a36Sopenharmony_ci regmap_reg_range(0x1820, 0x1827), 90762306a36Sopenharmony_ci regmap_reg_range(0x1830, 0x1837), 90862306a36Sopenharmony_ci regmap_reg_range(0x1840, 0x184b), 90962306a36Sopenharmony_ci regmap_reg_range(0x1900, 0x1907), 91062306a36Sopenharmony_ci regmap_reg_range(0x1914, 0x1915), 91162306a36Sopenharmony_ci regmap_reg_range(0x1a00, 0x1a03), 91262306a36Sopenharmony_ci regmap_reg_range(0x1a04, 0x1a07), 91362306a36Sopenharmony_ci regmap_reg_range(0x1b00, 0x1b01), 91462306a36Sopenharmony_ci regmap_reg_range(0x1b04, 0x1b04), 91562306a36Sopenharmony_ci 91662306a36Sopenharmony_ci /* port 2 */ 91762306a36Sopenharmony_ci regmap_reg_range(0x2000, 0x2001), 91862306a36Sopenharmony_ci regmap_reg_range(0x2013, 0x2013), 91962306a36Sopenharmony_ci regmap_reg_range(0x2017, 0x2017), 92062306a36Sopenharmony_ci regmap_reg_range(0x201b, 0x201b), 92162306a36Sopenharmony_ci regmap_reg_range(0x201f, 0x2020), 92262306a36Sopenharmony_ci regmap_reg_range(0x2030, 0x2030), 92362306a36Sopenharmony_ci regmap_reg_range(0x2100, 0x2115), 92462306a36Sopenharmony_ci regmap_reg_range(0x211a, 0x211f), 92562306a36Sopenharmony_ci regmap_reg_range(0x2122, 0x2127), 92662306a36Sopenharmony_ci regmap_reg_range(0x212a, 0x212b), 92762306a36Sopenharmony_ci regmap_reg_range(0x2136, 0x2139), 92862306a36Sopenharmony_ci regmap_reg_range(0x213e, 0x213f), 92962306a36Sopenharmony_ci regmap_reg_range(0x2400, 0x2401), 93062306a36Sopenharmony_ci regmap_reg_range(0x2403, 0x2403), 93162306a36Sopenharmony_ci regmap_reg_range(0x2410, 0x2417), 93262306a36Sopenharmony_ci regmap_reg_range(0x2420, 0x2423), 93362306a36Sopenharmony_ci regmap_reg_range(0x2500, 0x2507), 93462306a36Sopenharmony_ci regmap_reg_range(0x2600, 0x2612), 93562306a36Sopenharmony_ci regmap_reg_range(0x2800, 0x280f), 93662306a36Sopenharmony_ci regmap_reg_range(0x2820, 0x2827), 93762306a36Sopenharmony_ci regmap_reg_range(0x2830, 0x2837), 93862306a36Sopenharmony_ci regmap_reg_range(0x2840, 0x284b), 93962306a36Sopenharmony_ci regmap_reg_range(0x2900, 0x2907), 94062306a36Sopenharmony_ci regmap_reg_range(0x2914, 0x2915), 94162306a36Sopenharmony_ci regmap_reg_range(0x2a00, 0x2a03), 94262306a36Sopenharmony_ci regmap_reg_range(0x2a04, 0x2a07), 94362306a36Sopenharmony_ci regmap_reg_range(0x2b00, 0x2b01), 94462306a36Sopenharmony_ci regmap_reg_range(0x2b04, 0x2b04), 94562306a36Sopenharmony_ci 94662306a36Sopenharmony_ci /* port 3 */ 94762306a36Sopenharmony_ci regmap_reg_range(0x3000, 0x3001), 94862306a36Sopenharmony_ci regmap_reg_range(0x3013, 0x3013), 94962306a36Sopenharmony_ci regmap_reg_range(0x3017, 0x3017), 95062306a36Sopenharmony_ci regmap_reg_range(0x301b, 0x301b), 95162306a36Sopenharmony_ci regmap_reg_range(0x301f, 0x3020), 95262306a36Sopenharmony_ci regmap_reg_range(0x3030, 0x3030), 95362306a36Sopenharmony_ci regmap_reg_range(0x3100, 0x3115), 95462306a36Sopenharmony_ci regmap_reg_range(0x311a, 0x311f), 95562306a36Sopenharmony_ci regmap_reg_range(0x3122, 0x3127), 95662306a36Sopenharmony_ci regmap_reg_range(0x312a, 0x312b), 95762306a36Sopenharmony_ci regmap_reg_range(0x3136, 0x3139), 95862306a36Sopenharmony_ci regmap_reg_range(0x313e, 0x313f), 95962306a36Sopenharmony_ci regmap_reg_range(0x3400, 0x3401), 96062306a36Sopenharmony_ci regmap_reg_range(0x3403, 0x3403), 96162306a36Sopenharmony_ci regmap_reg_range(0x3410, 0x3417), 96262306a36Sopenharmony_ci regmap_reg_range(0x3420, 0x3423), 96362306a36Sopenharmony_ci regmap_reg_range(0x3500, 0x3507), 96462306a36Sopenharmony_ci regmap_reg_range(0x3600, 0x3612), 96562306a36Sopenharmony_ci regmap_reg_range(0x3800, 0x380f), 96662306a36Sopenharmony_ci regmap_reg_range(0x3820, 0x3827), 96762306a36Sopenharmony_ci regmap_reg_range(0x3830, 0x3837), 96862306a36Sopenharmony_ci regmap_reg_range(0x3840, 0x384b), 96962306a36Sopenharmony_ci regmap_reg_range(0x3900, 0x3907), 97062306a36Sopenharmony_ci regmap_reg_range(0x3914, 0x3915), 97162306a36Sopenharmony_ci regmap_reg_range(0x3a00, 0x3a03), 97262306a36Sopenharmony_ci regmap_reg_range(0x3a04, 0x3a07), 97362306a36Sopenharmony_ci regmap_reg_range(0x3b00, 0x3b01), 97462306a36Sopenharmony_ci regmap_reg_range(0x3b04, 0x3b04), 97562306a36Sopenharmony_ci 97662306a36Sopenharmony_ci /* port 4 */ 97762306a36Sopenharmony_ci regmap_reg_range(0x4000, 0x4001), 97862306a36Sopenharmony_ci regmap_reg_range(0x4013, 0x4013), 97962306a36Sopenharmony_ci regmap_reg_range(0x4017, 0x4017), 98062306a36Sopenharmony_ci regmap_reg_range(0x401b, 0x401b), 98162306a36Sopenharmony_ci regmap_reg_range(0x401f, 0x4020), 98262306a36Sopenharmony_ci regmap_reg_range(0x4030, 0x4030), 98362306a36Sopenharmony_ci regmap_reg_range(0x4100, 0x4115), 98462306a36Sopenharmony_ci regmap_reg_range(0x411a, 0x411f), 98562306a36Sopenharmony_ci regmap_reg_range(0x4122, 0x4127), 98662306a36Sopenharmony_ci regmap_reg_range(0x412a, 0x412b), 98762306a36Sopenharmony_ci regmap_reg_range(0x4136, 0x4139), 98862306a36Sopenharmony_ci regmap_reg_range(0x413e, 0x413f), 98962306a36Sopenharmony_ci regmap_reg_range(0x4400, 0x4401), 99062306a36Sopenharmony_ci regmap_reg_range(0x4403, 0x4403), 99162306a36Sopenharmony_ci regmap_reg_range(0x4410, 0x4417), 99262306a36Sopenharmony_ci regmap_reg_range(0x4420, 0x4423), 99362306a36Sopenharmony_ci regmap_reg_range(0x4500, 0x4507), 99462306a36Sopenharmony_ci regmap_reg_range(0x4600, 0x4612), 99562306a36Sopenharmony_ci regmap_reg_range(0x4800, 0x480f), 99662306a36Sopenharmony_ci regmap_reg_range(0x4820, 0x4827), 99762306a36Sopenharmony_ci regmap_reg_range(0x4830, 0x4837), 99862306a36Sopenharmony_ci regmap_reg_range(0x4840, 0x484b), 99962306a36Sopenharmony_ci regmap_reg_range(0x4900, 0x4907), 100062306a36Sopenharmony_ci regmap_reg_range(0x4914, 0x4915), 100162306a36Sopenharmony_ci regmap_reg_range(0x4a00, 0x4a03), 100262306a36Sopenharmony_ci regmap_reg_range(0x4a04, 0x4a07), 100362306a36Sopenharmony_ci regmap_reg_range(0x4b00, 0x4b01), 100462306a36Sopenharmony_ci regmap_reg_range(0x4b04, 0x4b04), 100562306a36Sopenharmony_ci 100662306a36Sopenharmony_ci /* port 5 */ 100762306a36Sopenharmony_ci regmap_reg_range(0x5000, 0x5001), 100862306a36Sopenharmony_ci regmap_reg_range(0x5013, 0x5013), 100962306a36Sopenharmony_ci regmap_reg_range(0x5017, 0x5017), 101062306a36Sopenharmony_ci regmap_reg_range(0x501b, 0x501b), 101162306a36Sopenharmony_ci regmap_reg_range(0x501f, 0x5020), 101262306a36Sopenharmony_ci regmap_reg_range(0x5030, 0x5030), 101362306a36Sopenharmony_ci regmap_reg_range(0x5100, 0x5115), 101462306a36Sopenharmony_ci regmap_reg_range(0x511a, 0x511f), 101562306a36Sopenharmony_ci regmap_reg_range(0x5122, 0x5127), 101662306a36Sopenharmony_ci regmap_reg_range(0x512a, 0x512b), 101762306a36Sopenharmony_ci regmap_reg_range(0x5136, 0x5139), 101862306a36Sopenharmony_ci regmap_reg_range(0x513e, 0x513f), 101962306a36Sopenharmony_ci regmap_reg_range(0x5400, 0x5401), 102062306a36Sopenharmony_ci regmap_reg_range(0x5403, 0x5403), 102162306a36Sopenharmony_ci regmap_reg_range(0x5410, 0x5417), 102262306a36Sopenharmony_ci regmap_reg_range(0x5420, 0x5423), 102362306a36Sopenharmony_ci regmap_reg_range(0x5500, 0x5507), 102462306a36Sopenharmony_ci regmap_reg_range(0x5600, 0x5612), 102562306a36Sopenharmony_ci regmap_reg_range(0x5800, 0x580f), 102662306a36Sopenharmony_ci regmap_reg_range(0x5820, 0x5827), 102762306a36Sopenharmony_ci regmap_reg_range(0x5830, 0x5837), 102862306a36Sopenharmony_ci regmap_reg_range(0x5840, 0x584b), 102962306a36Sopenharmony_ci regmap_reg_range(0x5900, 0x5907), 103062306a36Sopenharmony_ci regmap_reg_range(0x5914, 0x5915), 103162306a36Sopenharmony_ci regmap_reg_range(0x5a00, 0x5a03), 103262306a36Sopenharmony_ci regmap_reg_range(0x5a04, 0x5a07), 103362306a36Sopenharmony_ci regmap_reg_range(0x5b00, 0x5b01), 103462306a36Sopenharmony_ci regmap_reg_range(0x5b04, 0x5b04), 103562306a36Sopenharmony_ci 103662306a36Sopenharmony_ci /* port 6 */ 103762306a36Sopenharmony_ci regmap_reg_range(0x6000, 0x6001), 103862306a36Sopenharmony_ci regmap_reg_range(0x6013, 0x6013), 103962306a36Sopenharmony_ci regmap_reg_range(0x6017, 0x6017), 104062306a36Sopenharmony_ci regmap_reg_range(0x601b, 0x601b), 104162306a36Sopenharmony_ci regmap_reg_range(0x601f, 0x6020), 104262306a36Sopenharmony_ci regmap_reg_range(0x6030, 0x6030), 104362306a36Sopenharmony_ci regmap_reg_range(0x6100, 0x6115), 104462306a36Sopenharmony_ci regmap_reg_range(0x611a, 0x611f), 104562306a36Sopenharmony_ci regmap_reg_range(0x6122, 0x6127), 104662306a36Sopenharmony_ci regmap_reg_range(0x612a, 0x612b), 104762306a36Sopenharmony_ci regmap_reg_range(0x6136, 0x6139), 104862306a36Sopenharmony_ci regmap_reg_range(0x613e, 0x613f), 104962306a36Sopenharmony_ci regmap_reg_range(0x6300, 0x6301), 105062306a36Sopenharmony_ci regmap_reg_range(0x6400, 0x6401), 105162306a36Sopenharmony_ci regmap_reg_range(0x6403, 0x6403), 105262306a36Sopenharmony_ci regmap_reg_range(0x6410, 0x6417), 105362306a36Sopenharmony_ci regmap_reg_range(0x6420, 0x6423), 105462306a36Sopenharmony_ci regmap_reg_range(0x6500, 0x6507), 105562306a36Sopenharmony_ci regmap_reg_range(0x6600, 0x6612), 105662306a36Sopenharmony_ci regmap_reg_range(0x6800, 0x680f), 105762306a36Sopenharmony_ci regmap_reg_range(0x6820, 0x6827), 105862306a36Sopenharmony_ci regmap_reg_range(0x6830, 0x6837), 105962306a36Sopenharmony_ci regmap_reg_range(0x6840, 0x684b), 106062306a36Sopenharmony_ci regmap_reg_range(0x6900, 0x6907), 106162306a36Sopenharmony_ci regmap_reg_range(0x6914, 0x6915), 106262306a36Sopenharmony_ci regmap_reg_range(0x6a00, 0x6a03), 106362306a36Sopenharmony_ci regmap_reg_range(0x6a04, 0x6a07), 106462306a36Sopenharmony_ci regmap_reg_range(0x6b00, 0x6b01), 106562306a36Sopenharmony_ci regmap_reg_range(0x6b04, 0x6b04), 106662306a36Sopenharmony_ci}; 106762306a36Sopenharmony_ci 106862306a36Sopenharmony_cistatic const struct regmap_access_table ksz9896_register_set = { 106962306a36Sopenharmony_ci .yes_ranges = ksz9896_valid_regs, 107062306a36Sopenharmony_ci .n_yes_ranges = ARRAY_SIZE(ksz9896_valid_regs), 107162306a36Sopenharmony_ci}; 107262306a36Sopenharmony_ci 107362306a36Sopenharmony_cistatic const struct regmap_range ksz8873_valid_regs[] = { 107462306a36Sopenharmony_ci regmap_reg_range(0x00, 0x01), 107562306a36Sopenharmony_ci /* global control register */ 107662306a36Sopenharmony_ci regmap_reg_range(0x02, 0x0f), 107762306a36Sopenharmony_ci 107862306a36Sopenharmony_ci /* port registers */ 107962306a36Sopenharmony_ci regmap_reg_range(0x10, 0x1d), 108062306a36Sopenharmony_ci regmap_reg_range(0x1e, 0x1f), 108162306a36Sopenharmony_ci regmap_reg_range(0x20, 0x2d), 108262306a36Sopenharmony_ci regmap_reg_range(0x2e, 0x2f), 108362306a36Sopenharmony_ci regmap_reg_range(0x30, 0x39), 108462306a36Sopenharmony_ci regmap_reg_range(0x3f, 0x3f), 108562306a36Sopenharmony_ci 108662306a36Sopenharmony_ci /* advanced control registers */ 108762306a36Sopenharmony_ci regmap_reg_range(0x60, 0x6f), 108862306a36Sopenharmony_ci regmap_reg_range(0x70, 0x75), 108962306a36Sopenharmony_ci regmap_reg_range(0x76, 0x78), 109062306a36Sopenharmony_ci regmap_reg_range(0x79, 0x7a), 109162306a36Sopenharmony_ci regmap_reg_range(0x7b, 0x83), 109262306a36Sopenharmony_ci regmap_reg_range(0x8e, 0x99), 109362306a36Sopenharmony_ci regmap_reg_range(0x9a, 0xa5), 109462306a36Sopenharmony_ci regmap_reg_range(0xa6, 0xa6), 109562306a36Sopenharmony_ci regmap_reg_range(0xa7, 0xaa), 109662306a36Sopenharmony_ci regmap_reg_range(0xab, 0xae), 109762306a36Sopenharmony_ci regmap_reg_range(0xaf, 0xba), 109862306a36Sopenharmony_ci regmap_reg_range(0xbb, 0xbc), 109962306a36Sopenharmony_ci regmap_reg_range(0xbd, 0xbd), 110062306a36Sopenharmony_ci regmap_reg_range(0xc0, 0xc0), 110162306a36Sopenharmony_ci regmap_reg_range(0xc2, 0xc2), 110262306a36Sopenharmony_ci regmap_reg_range(0xc3, 0xc3), 110362306a36Sopenharmony_ci regmap_reg_range(0xc4, 0xc4), 110462306a36Sopenharmony_ci regmap_reg_range(0xc6, 0xc6), 110562306a36Sopenharmony_ci}; 110662306a36Sopenharmony_ci 110762306a36Sopenharmony_cistatic const struct regmap_access_table ksz8873_register_set = { 110862306a36Sopenharmony_ci .yes_ranges = ksz8873_valid_regs, 110962306a36Sopenharmony_ci .n_yes_ranges = ARRAY_SIZE(ksz8873_valid_regs), 111062306a36Sopenharmony_ci}; 111162306a36Sopenharmony_ci 111262306a36Sopenharmony_ciconst struct ksz_chip_data ksz_switch_chips[] = { 111362306a36Sopenharmony_ci [KSZ8563] = { 111462306a36Sopenharmony_ci .chip_id = KSZ8563_CHIP_ID, 111562306a36Sopenharmony_ci .dev_name = "KSZ8563", 111662306a36Sopenharmony_ci .num_vlans = 4096, 111762306a36Sopenharmony_ci .num_alus = 4096, 111862306a36Sopenharmony_ci .num_statics = 16, 111962306a36Sopenharmony_ci .cpu_ports = 0x07, /* can be configured as cpu port */ 112062306a36Sopenharmony_ci .port_cnt = 3, /* total port count */ 112162306a36Sopenharmony_ci .port_nirqs = 3, 112262306a36Sopenharmony_ci .num_tx_queues = 4, 112362306a36Sopenharmony_ci .tc_cbs_supported = true, 112462306a36Sopenharmony_ci .tc_ets_supported = true, 112562306a36Sopenharmony_ci .ops = &ksz9477_dev_ops, 112662306a36Sopenharmony_ci .mib_names = ksz9477_mib_names, 112762306a36Sopenharmony_ci .mib_cnt = ARRAY_SIZE(ksz9477_mib_names), 112862306a36Sopenharmony_ci .reg_mib_cnt = MIB_COUNTER_NUM, 112962306a36Sopenharmony_ci .regs = ksz9477_regs, 113062306a36Sopenharmony_ci .masks = ksz9477_masks, 113162306a36Sopenharmony_ci .shifts = ksz9477_shifts, 113262306a36Sopenharmony_ci .xmii_ctrl0 = ksz9477_xmii_ctrl0, 113362306a36Sopenharmony_ci .xmii_ctrl1 = ksz8795_xmii_ctrl1, /* Same as ksz8795 */ 113462306a36Sopenharmony_ci .supports_mii = {false, false, true}, 113562306a36Sopenharmony_ci .supports_rmii = {false, false, true}, 113662306a36Sopenharmony_ci .supports_rgmii = {false, false, true}, 113762306a36Sopenharmony_ci .internal_phy = {true, true, false}, 113862306a36Sopenharmony_ci .gbit_capable = {false, false, true}, 113962306a36Sopenharmony_ci .wr_table = &ksz8563_register_set, 114062306a36Sopenharmony_ci .rd_table = &ksz8563_register_set, 114162306a36Sopenharmony_ci }, 114262306a36Sopenharmony_ci 114362306a36Sopenharmony_ci [KSZ8795] = { 114462306a36Sopenharmony_ci .chip_id = KSZ8795_CHIP_ID, 114562306a36Sopenharmony_ci .dev_name = "KSZ8795", 114662306a36Sopenharmony_ci .num_vlans = 4096, 114762306a36Sopenharmony_ci .num_alus = 0, 114862306a36Sopenharmony_ci .num_statics = 8, 114962306a36Sopenharmony_ci .cpu_ports = 0x10, /* can be configured as cpu port */ 115062306a36Sopenharmony_ci .port_cnt = 5, /* total cpu and user ports */ 115162306a36Sopenharmony_ci .num_tx_queues = 4, 115262306a36Sopenharmony_ci .ops = &ksz8_dev_ops, 115362306a36Sopenharmony_ci .ksz87xx_eee_link_erratum = true, 115462306a36Sopenharmony_ci .mib_names = ksz9477_mib_names, 115562306a36Sopenharmony_ci .mib_cnt = ARRAY_SIZE(ksz9477_mib_names), 115662306a36Sopenharmony_ci .reg_mib_cnt = MIB_COUNTER_NUM, 115762306a36Sopenharmony_ci .regs = ksz8795_regs, 115862306a36Sopenharmony_ci .masks = ksz8795_masks, 115962306a36Sopenharmony_ci .shifts = ksz8795_shifts, 116062306a36Sopenharmony_ci .xmii_ctrl0 = ksz8795_xmii_ctrl0, 116162306a36Sopenharmony_ci .xmii_ctrl1 = ksz8795_xmii_ctrl1, 116262306a36Sopenharmony_ci .supports_mii = {false, false, false, false, true}, 116362306a36Sopenharmony_ci .supports_rmii = {false, false, false, false, true}, 116462306a36Sopenharmony_ci .supports_rgmii = {false, false, false, false, true}, 116562306a36Sopenharmony_ci .internal_phy = {true, true, true, true, false}, 116662306a36Sopenharmony_ci }, 116762306a36Sopenharmony_ci 116862306a36Sopenharmony_ci [KSZ8794] = { 116962306a36Sopenharmony_ci /* WARNING 117062306a36Sopenharmony_ci * ======= 117162306a36Sopenharmony_ci * KSZ8794 is similar to KSZ8795, except the port map 117262306a36Sopenharmony_ci * contains a gap between external and CPU ports, the 117362306a36Sopenharmony_ci * port map is NOT continuous. The per-port register 117462306a36Sopenharmony_ci * map is shifted accordingly too, i.e. registers at 117562306a36Sopenharmony_ci * offset 0x40 are NOT used on KSZ8794 and they ARE 117662306a36Sopenharmony_ci * used on KSZ8795 for external port 3. 117762306a36Sopenharmony_ci * external cpu 117862306a36Sopenharmony_ci * KSZ8794 0,1,2 4 117962306a36Sopenharmony_ci * KSZ8795 0,1,2,3 4 118062306a36Sopenharmony_ci * KSZ8765 0,1,2,3 4 118162306a36Sopenharmony_ci * port_cnt is configured as 5, even though it is 4 118262306a36Sopenharmony_ci */ 118362306a36Sopenharmony_ci .chip_id = KSZ8794_CHIP_ID, 118462306a36Sopenharmony_ci .dev_name = "KSZ8794", 118562306a36Sopenharmony_ci .num_vlans = 4096, 118662306a36Sopenharmony_ci .num_alus = 0, 118762306a36Sopenharmony_ci .num_statics = 8, 118862306a36Sopenharmony_ci .cpu_ports = 0x10, /* can be configured as cpu port */ 118962306a36Sopenharmony_ci .port_cnt = 5, /* total cpu and user ports */ 119062306a36Sopenharmony_ci .num_tx_queues = 4, 119162306a36Sopenharmony_ci .ops = &ksz8_dev_ops, 119262306a36Sopenharmony_ci .ksz87xx_eee_link_erratum = true, 119362306a36Sopenharmony_ci .mib_names = ksz9477_mib_names, 119462306a36Sopenharmony_ci .mib_cnt = ARRAY_SIZE(ksz9477_mib_names), 119562306a36Sopenharmony_ci .reg_mib_cnt = MIB_COUNTER_NUM, 119662306a36Sopenharmony_ci .regs = ksz8795_regs, 119762306a36Sopenharmony_ci .masks = ksz8795_masks, 119862306a36Sopenharmony_ci .shifts = ksz8795_shifts, 119962306a36Sopenharmony_ci .xmii_ctrl0 = ksz8795_xmii_ctrl0, 120062306a36Sopenharmony_ci .xmii_ctrl1 = ksz8795_xmii_ctrl1, 120162306a36Sopenharmony_ci .supports_mii = {false, false, false, false, true}, 120262306a36Sopenharmony_ci .supports_rmii = {false, false, false, false, true}, 120362306a36Sopenharmony_ci .supports_rgmii = {false, false, false, false, true}, 120462306a36Sopenharmony_ci .internal_phy = {true, true, true, false, false}, 120562306a36Sopenharmony_ci }, 120662306a36Sopenharmony_ci 120762306a36Sopenharmony_ci [KSZ8765] = { 120862306a36Sopenharmony_ci .chip_id = KSZ8765_CHIP_ID, 120962306a36Sopenharmony_ci .dev_name = "KSZ8765", 121062306a36Sopenharmony_ci .num_vlans = 4096, 121162306a36Sopenharmony_ci .num_alus = 0, 121262306a36Sopenharmony_ci .num_statics = 8, 121362306a36Sopenharmony_ci .cpu_ports = 0x10, /* can be configured as cpu port */ 121462306a36Sopenharmony_ci .port_cnt = 5, /* total cpu and user ports */ 121562306a36Sopenharmony_ci .num_tx_queues = 4, 121662306a36Sopenharmony_ci .ops = &ksz8_dev_ops, 121762306a36Sopenharmony_ci .ksz87xx_eee_link_erratum = true, 121862306a36Sopenharmony_ci .mib_names = ksz9477_mib_names, 121962306a36Sopenharmony_ci .mib_cnt = ARRAY_SIZE(ksz9477_mib_names), 122062306a36Sopenharmony_ci .reg_mib_cnt = MIB_COUNTER_NUM, 122162306a36Sopenharmony_ci .regs = ksz8795_regs, 122262306a36Sopenharmony_ci .masks = ksz8795_masks, 122362306a36Sopenharmony_ci .shifts = ksz8795_shifts, 122462306a36Sopenharmony_ci .xmii_ctrl0 = ksz8795_xmii_ctrl0, 122562306a36Sopenharmony_ci .xmii_ctrl1 = ksz8795_xmii_ctrl1, 122662306a36Sopenharmony_ci .supports_mii = {false, false, false, false, true}, 122762306a36Sopenharmony_ci .supports_rmii = {false, false, false, false, true}, 122862306a36Sopenharmony_ci .supports_rgmii = {false, false, false, false, true}, 122962306a36Sopenharmony_ci .internal_phy = {true, true, true, true, false}, 123062306a36Sopenharmony_ci }, 123162306a36Sopenharmony_ci 123262306a36Sopenharmony_ci [KSZ8830] = { 123362306a36Sopenharmony_ci .chip_id = KSZ8830_CHIP_ID, 123462306a36Sopenharmony_ci .dev_name = "KSZ8863/KSZ8873", 123562306a36Sopenharmony_ci .num_vlans = 16, 123662306a36Sopenharmony_ci .num_alus = 0, 123762306a36Sopenharmony_ci .num_statics = 8, 123862306a36Sopenharmony_ci .cpu_ports = 0x4, /* can be configured as cpu port */ 123962306a36Sopenharmony_ci .port_cnt = 3, 124062306a36Sopenharmony_ci .num_tx_queues = 4, 124162306a36Sopenharmony_ci .ops = &ksz8_dev_ops, 124262306a36Sopenharmony_ci .mib_names = ksz88xx_mib_names, 124362306a36Sopenharmony_ci .mib_cnt = ARRAY_SIZE(ksz88xx_mib_names), 124462306a36Sopenharmony_ci .reg_mib_cnt = MIB_COUNTER_NUM, 124562306a36Sopenharmony_ci .regs = ksz8863_regs, 124662306a36Sopenharmony_ci .masks = ksz8863_masks, 124762306a36Sopenharmony_ci .shifts = ksz8863_shifts, 124862306a36Sopenharmony_ci .supports_mii = {false, false, true}, 124962306a36Sopenharmony_ci .supports_rmii = {false, false, true}, 125062306a36Sopenharmony_ci .internal_phy = {true, true, false}, 125162306a36Sopenharmony_ci .wr_table = &ksz8873_register_set, 125262306a36Sopenharmony_ci .rd_table = &ksz8873_register_set, 125362306a36Sopenharmony_ci }, 125462306a36Sopenharmony_ci 125562306a36Sopenharmony_ci [KSZ9477] = { 125662306a36Sopenharmony_ci .chip_id = KSZ9477_CHIP_ID, 125762306a36Sopenharmony_ci .dev_name = "KSZ9477", 125862306a36Sopenharmony_ci .num_vlans = 4096, 125962306a36Sopenharmony_ci .num_alus = 4096, 126062306a36Sopenharmony_ci .num_statics = 16, 126162306a36Sopenharmony_ci .cpu_ports = 0x7F, /* can be configured as cpu port */ 126262306a36Sopenharmony_ci .port_cnt = 7, /* total physical port count */ 126362306a36Sopenharmony_ci .port_nirqs = 4, 126462306a36Sopenharmony_ci .num_tx_queues = 4, 126562306a36Sopenharmony_ci .tc_cbs_supported = true, 126662306a36Sopenharmony_ci .tc_ets_supported = true, 126762306a36Sopenharmony_ci .ops = &ksz9477_dev_ops, 126862306a36Sopenharmony_ci .mib_names = ksz9477_mib_names, 126962306a36Sopenharmony_ci .mib_cnt = ARRAY_SIZE(ksz9477_mib_names), 127062306a36Sopenharmony_ci .reg_mib_cnt = MIB_COUNTER_NUM, 127162306a36Sopenharmony_ci .regs = ksz9477_regs, 127262306a36Sopenharmony_ci .masks = ksz9477_masks, 127362306a36Sopenharmony_ci .shifts = ksz9477_shifts, 127462306a36Sopenharmony_ci .xmii_ctrl0 = ksz9477_xmii_ctrl0, 127562306a36Sopenharmony_ci .xmii_ctrl1 = ksz9477_xmii_ctrl1, 127662306a36Sopenharmony_ci .supports_mii = {false, false, false, false, 127762306a36Sopenharmony_ci false, true, false}, 127862306a36Sopenharmony_ci .supports_rmii = {false, false, false, false, 127962306a36Sopenharmony_ci false, true, false}, 128062306a36Sopenharmony_ci .supports_rgmii = {false, false, false, false, 128162306a36Sopenharmony_ci false, true, false}, 128262306a36Sopenharmony_ci .internal_phy = {true, true, true, true, 128362306a36Sopenharmony_ci true, false, false}, 128462306a36Sopenharmony_ci .gbit_capable = {true, true, true, true, true, true, true}, 128562306a36Sopenharmony_ci .wr_table = &ksz9477_register_set, 128662306a36Sopenharmony_ci .rd_table = &ksz9477_register_set, 128762306a36Sopenharmony_ci }, 128862306a36Sopenharmony_ci 128962306a36Sopenharmony_ci [KSZ9896] = { 129062306a36Sopenharmony_ci .chip_id = KSZ9896_CHIP_ID, 129162306a36Sopenharmony_ci .dev_name = "KSZ9896", 129262306a36Sopenharmony_ci .num_vlans = 4096, 129362306a36Sopenharmony_ci .num_alus = 4096, 129462306a36Sopenharmony_ci .num_statics = 16, 129562306a36Sopenharmony_ci .cpu_ports = 0x3F, /* can be configured as cpu port */ 129662306a36Sopenharmony_ci .port_cnt = 6, /* total physical port count */ 129762306a36Sopenharmony_ci .port_nirqs = 2, 129862306a36Sopenharmony_ci .num_tx_queues = 4, 129962306a36Sopenharmony_ci .ops = &ksz9477_dev_ops, 130062306a36Sopenharmony_ci .mib_names = ksz9477_mib_names, 130162306a36Sopenharmony_ci .mib_cnt = ARRAY_SIZE(ksz9477_mib_names), 130262306a36Sopenharmony_ci .reg_mib_cnt = MIB_COUNTER_NUM, 130362306a36Sopenharmony_ci .regs = ksz9477_regs, 130462306a36Sopenharmony_ci .masks = ksz9477_masks, 130562306a36Sopenharmony_ci .shifts = ksz9477_shifts, 130662306a36Sopenharmony_ci .xmii_ctrl0 = ksz9477_xmii_ctrl0, 130762306a36Sopenharmony_ci .xmii_ctrl1 = ksz9477_xmii_ctrl1, 130862306a36Sopenharmony_ci .supports_mii = {false, false, false, false, 130962306a36Sopenharmony_ci false, true}, 131062306a36Sopenharmony_ci .supports_rmii = {false, false, false, false, 131162306a36Sopenharmony_ci false, true}, 131262306a36Sopenharmony_ci .supports_rgmii = {false, false, false, false, 131362306a36Sopenharmony_ci false, true}, 131462306a36Sopenharmony_ci .internal_phy = {true, true, true, true, 131562306a36Sopenharmony_ci true, false}, 131662306a36Sopenharmony_ci .gbit_capable = {true, true, true, true, true, true}, 131762306a36Sopenharmony_ci .wr_table = &ksz9896_register_set, 131862306a36Sopenharmony_ci .rd_table = &ksz9896_register_set, 131962306a36Sopenharmony_ci }, 132062306a36Sopenharmony_ci 132162306a36Sopenharmony_ci [KSZ9897] = { 132262306a36Sopenharmony_ci .chip_id = KSZ9897_CHIP_ID, 132362306a36Sopenharmony_ci .dev_name = "KSZ9897", 132462306a36Sopenharmony_ci .num_vlans = 4096, 132562306a36Sopenharmony_ci .num_alus = 4096, 132662306a36Sopenharmony_ci .num_statics = 16, 132762306a36Sopenharmony_ci .cpu_ports = 0x7F, /* can be configured as cpu port */ 132862306a36Sopenharmony_ci .port_cnt = 7, /* total physical port count */ 132962306a36Sopenharmony_ci .port_nirqs = 2, 133062306a36Sopenharmony_ci .num_tx_queues = 4, 133162306a36Sopenharmony_ci .ops = &ksz9477_dev_ops, 133262306a36Sopenharmony_ci .mib_names = ksz9477_mib_names, 133362306a36Sopenharmony_ci .mib_cnt = ARRAY_SIZE(ksz9477_mib_names), 133462306a36Sopenharmony_ci .reg_mib_cnt = MIB_COUNTER_NUM, 133562306a36Sopenharmony_ci .regs = ksz9477_regs, 133662306a36Sopenharmony_ci .masks = ksz9477_masks, 133762306a36Sopenharmony_ci .shifts = ksz9477_shifts, 133862306a36Sopenharmony_ci .xmii_ctrl0 = ksz9477_xmii_ctrl0, 133962306a36Sopenharmony_ci .xmii_ctrl1 = ksz9477_xmii_ctrl1, 134062306a36Sopenharmony_ci .supports_mii = {false, false, false, false, 134162306a36Sopenharmony_ci false, true, true}, 134262306a36Sopenharmony_ci .supports_rmii = {false, false, false, false, 134362306a36Sopenharmony_ci false, true, true}, 134462306a36Sopenharmony_ci .supports_rgmii = {false, false, false, false, 134562306a36Sopenharmony_ci false, true, true}, 134662306a36Sopenharmony_ci .internal_phy = {true, true, true, true, 134762306a36Sopenharmony_ci true, false, false}, 134862306a36Sopenharmony_ci .gbit_capable = {true, true, true, true, true, true, true}, 134962306a36Sopenharmony_ci }, 135062306a36Sopenharmony_ci 135162306a36Sopenharmony_ci [KSZ9893] = { 135262306a36Sopenharmony_ci .chip_id = KSZ9893_CHIP_ID, 135362306a36Sopenharmony_ci .dev_name = "KSZ9893", 135462306a36Sopenharmony_ci .num_vlans = 4096, 135562306a36Sopenharmony_ci .num_alus = 4096, 135662306a36Sopenharmony_ci .num_statics = 16, 135762306a36Sopenharmony_ci .cpu_ports = 0x07, /* can be configured as cpu port */ 135862306a36Sopenharmony_ci .port_cnt = 3, /* total port count */ 135962306a36Sopenharmony_ci .port_nirqs = 2, 136062306a36Sopenharmony_ci .num_tx_queues = 4, 136162306a36Sopenharmony_ci .ops = &ksz9477_dev_ops, 136262306a36Sopenharmony_ci .mib_names = ksz9477_mib_names, 136362306a36Sopenharmony_ci .mib_cnt = ARRAY_SIZE(ksz9477_mib_names), 136462306a36Sopenharmony_ci .reg_mib_cnt = MIB_COUNTER_NUM, 136562306a36Sopenharmony_ci .regs = ksz9477_regs, 136662306a36Sopenharmony_ci .masks = ksz9477_masks, 136762306a36Sopenharmony_ci .shifts = ksz9477_shifts, 136862306a36Sopenharmony_ci .xmii_ctrl0 = ksz9477_xmii_ctrl0, 136962306a36Sopenharmony_ci .xmii_ctrl1 = ksz8795_xmii_ctrl1, /* Same as ksz8795 */ 137062306a36Sopenharmony_ci .supports_mii = {false, false, true}, 137162306a36Sopenharmony_ci .supports_rmii = {false, false, true}, 137262306a36Sopenharmony_ci .supports_rgmii = {false, false, true}, 137362306a36Sopenharmony_ci .internal_phy = {true, true, false}, 137462306a36Sopenharmony_ci .gbit_capable = {true, true, true}, 137562306a36Sopenharmony_ci }, 137662306a36Sopenharmony_ci 137762306a36Sopenharmony_ci [KSZ9563] = { 137862306a36Sopenharmony_ci .chip_id = KSZ9563_CHIP_ID, 137962306a36Sopenharmony_ci .dev_name = "KSZ9563", 138062306a36Sopenharmony_ci .num_vlans = 4096, 138162306a36Sopenharmony_ci .num_alus = 4096, 138262306a36Sopenharmony_ci .num_statics = 16, 138362306a36Sopenharmony_ci .cpu_ports = 0x07, /* can be configured as cpu port */ 138462306a36Sopenharmony_ci .port_cnt = 3, /* total port count */ 138562306a36Sopenharmony_ci .port_nirqs = 3, 138662306a36Sopenharmony_ci .num_tx_queues = 4, 138762306a36Sopenharmony_ci .tc_cbs_supported = true, 138862306a36Sopenharmony_ci .tc_ets_supported = true, 138962306a36Sopenharmony_ci .ops = &ksz9477_dev_ops, 139062306a36Sopenharmony_ci .mib_names = ksz9477_mib_names, 139162306a36Sopenharmony_ci .mib_cnt = ARRAY_SIZE(ksz9477_mib_names), 139262306a36Sopenharmony_ci .reg_mib_cnt = MIB_COUNTER_NUM, 139362306a36Sopenharmony_ci .regs = ksz9477_regs, 139462306a36Sopenharmony_ci .masks = ksz9477_masks, 139562306a36Sopenharmony_ci .shifts = ksz9477_shifts, 139662306a36Sopenharmony_ci .xmii_ctrl0 = ksz9477_xmii_ctrl0, 139762306a36Sopenharmony_ci .xmii_ctrl1 = ksz8795_xmii_ctrl1, /* Same as ksz8795 */ 139862306a36Sopenharmony_ci .supports_mii = {false, false, true}, 139962306a36Sopenharmony_ci .supports_rmii = {false, false, true}, 140062306a36Sopenharmony_ci .supports_rgmii = {false, false, true}, 140162306a36Sopenharmony_ci .internal_phy = {true, true, false}, 140262306a36Sopenharmony_ci .gbit_capable = {true, true, true}, 140362306a36Sopenharmony_ci }, 140462306a36Sopenharmony_ci 140562306a36Sopenharmony_ci [KSZ9567] = { 140662306a36Sopenharmony_ci .chip_id = KSZ9567_CHIP_ID, 140762306a36Sopenharmony_ci .dev_name = "KSZ9567", 140862306a36Sopenharmony_ci .num_vlans = 4096, 140962306a36Sopenharmony_ci .num_alus = 4096, 141062306a36Sopenharmony_ci .num_statics = 16, 141162306a36Sopenharmony_ci .cpu_ports = 0x7F, /* can be configured as cpu port */ 141262306a36Sopenharmony_ci .port_cnt = 7, /* total physical port count */ 141362306a36Sopenharmony_ci .port_nirqs = 3, 141462306a36Sopenharmony_ci .num_tx_queues = 4, 141562306a36Sopenharmony_ci .tc_cbs_supported = true, 141662306a36Sopenharmony_ci .tc_ets_supported = true, 141762306a36Sopenharmony_ci .ops = &ksz9477_dev_ops, 141862306a36Sopenharmony_ci .mib_names = ksz9477_mib_names, 141962306a36Sopenharmony_ci .mib_cnt = ARRAY_SIZE(ksz9477_mib_names), 142062306a36Sopenharmony_ci .reg_mib_cnt = MIB_COUNTER_NUM, 142162306a36Sopenharmony_ci .regs = ksz9477_regs, 142262306a36Sopenharmony_ci .masks = ksz9477_masks, 142362306a36Sopenharmony_ci .shifts = ksz9477_shifts, 142462306a36Sopenharmony_ci .xmii_ctrl0 = ksz9477_xmii_ctrl0, 142562306a36Sopenharmony_ci .xmii_ctrl1 = ksz9477_xmii_ctrl1, 142662306a36Sopenharmony_ci .supports_mii = {false, false, false, false, 142762306a36Sopenharmony_ci false, true, true}, 142862306a36Sopenharmony_ci .supports_rmii = {false, false, false, false, 142962306a36Sopenharmony_ci false, true, true}, 143062306a36Sopenharmony_ci .supports_rgmii = {false, false, false, false, 143162306a36Sopenharmony_ci false, true, true}, 143262306a36Sopenharmony_ci .internal_phy = {true, true, true, true, 143362306a36Sopenharmony_ci true, false, false}, 143462306a36Sopenharmony_ci .gbit_capable = {true, true, true, true, true, true, true}, 143562306a36Sopenharmony_ci }, 143662306a36Sopenharmony_ci 143762306a36Sopenharmony_ci [LAN9370] = { 143862306a36Sopenharmony_ci .chip_id = LAN9370_CHIP_ID, 143962306a36Sopenharmony_ci .dev_name = "LAN9370", 144062306a36Sopenharmony_ci .num_vlans = 4096, 144162306a36Sopenharmony_ci .num_alus = 1024, 144262306a36Sopenharmony_ci .num_statics = 256, 144362306a36Sopenharmony_ci .cpu_ports = 0x10, /* can be configured as cpu port */ 144462306a36Sopenharmony_ci .port_cnt = 5, /* total physical port count */ 144562306a36Sopenharmony_ci .port_nirqs = 6, 144662306a36Sopenharmony_ci .num_tx_queues = 8, 144762306a36Sopenharmony_ci .tc_cbs_supported = true, 144862306a36Sopenharmony_ci .tc_ets_supported = true, 144962306a36Sopenharmony_ci .ops = &lan937x_dev_ops, 145062306a36Sopenharmony_ci .mib_names = ksz9477_mib_names, 145162306a36Sopenharmony_ci .mib_cnt = ARRAY_SIZE(ksz9477_mib_names), 145262306a36Sopenharmony_ci .reg_mib_cnt = MIB_COUNTER_NUM, 145362306a36Sopenharmony_ci .regs = ksz9477_regs, 145462306a36Sopenharmony_ci .masks = lan937x_masks, 145562306a36Sopenharmony_ci .shifts = lan937x_shifts, 145662306a36Sopenharmony_ci .xmii_ctrl0 = ksz9477_xmii_ctrl0, 145762306a36Sopenharmony_ci .xmii_ctrl1 = ksz9477_xmii_ctrl1, 145862306a36Sopenharmony_ci .supports_mii = {false, false, false, false, true}, 145962306a36Sopenharmony_ci .supports_rmii = {false, false, false, false, true}, 146062306a36Sopenharmony_ci .supports_rgmii = {false, false, false, false, true}, 146162306a36Sopenharmony_ci .internal_phy = {true, true, true, true, false}, 146262306a36Sopenharmony_ci }, 146362306a36Sopenharmony_ci 146462306a36Sopenharmony_ci [LAN9371] = { 146562306a36Sopenharmony_ci .chip_id = LAN9371_CHIP_ID, 146662306a36Sopenharmony_ci .dev_name = "LAN9371", 146762306a36Sopenharmony_ci .num_vlans = 4096, 146862306a36Sopenharmony_ci .num_alus = 1024, 146962306a36Sopenharmony_ci .num_statics = 256, 147062306a36Sopenharmony_ci .cpu_ports = 0x30, /* can be configured as cpu port */ 147162306a36Sopenharmony_ci .port_cnt = 6, /* total physical port count */ 147262306a36Sopenharmony_ci .port_nirqs = 6, 147362306a36Sopenharmony_ci .num_tx_queues = 8, 147462306a36Sopenharmony_ci .tc_cbs_supported = true, 147562306a36Sopenharmony_ci .tc_ets_supported = true, 147662306a36Sopenharmony_ci .ops = &lan937x_dev_ops, 147762306a36Sopenharmony_ci .mib_names = ksz9477_mib_names, 147862306a36Sopenharmony_ci .mib_cnt = ARRAY_SIZE(ksz9477_mib_names), 147962306a36Sopenharmony_ci .reg_mib_cnt = MIB_COUNTER_NUM, 148062306a36Sopenharmony_ci .regs = ksz9477_regs, 148162306a36Sopenharmony_ci .masks = lan937x_masks, 148262306a36Sopenharmony_ci .shifts = lan937x_shifts, 148362306a36Sopenharmony_ci .xmii_ctrl0 = ksz9477_xmii_ctrl0, 148462306a36Sopenharmony_ci .xmii_ctrl1 = ksz9477_xmii_ctrl1, 148562306a36Sopenharmony_ci .supports_mii = {false, false, false, false, true, true}, 148662306a36Sopenharmony_ci .supports_rmii = {false, false, false, false, true, true}, 148762306a36Sopenharmony_ci .supports_rgmii = {false, false, false, false, true, true}, 148862306a36Sopenharmony_ci .internal_phy = {true, true, true, true, false, false}, 148962306a36Sopenharmony_ci }, 149062306a36Sopenharmony_ci 149162306a36Sopenharmony_ci [LAN9372] = { 149262306a36Sopenharmony_ci .chip_id = LAN9372_CHIP_ID, 149362306a36Sopenharmony_ci .dev_name = "LAN9372", 149462306a36Sopenharmony_ci .num_vlans = 4096, 149562306a36Sopenharmony_ci .num_alus = 1024, 149662306a36Sopenharmony_ci .num_statics = 256, 149762306a36Sopenharmony_ci .cpu_ports = 0x30, /* can be configured as cpu port */ 149862306a36Sopenharmony_ci .port_cnt = 8, /* total physical port count */ 149962306a36Sopenharmony_ci .port_nirqs = 6, 150062306a36Sopenharmony_ci .num_tx_queues = 8, 150162306a36Sopenharmony_ci .tc_cbs_supported = true, 150262306a36Sopenharmony_ci .tc_ets_supported = true, 150362306a36Sopenharmony_ci .ops = &lan937x_dev_ops, 150462306a36Sopenharmony_ci .mib_names = ksz9477_mib_names, 150562306a36Sopenharmony_ci .mib_cnt = ARRAY_SIZE(ksz9477_mib_names), 150662306a36Sopenharmony_ci .reg_mib_cnt = MIB_COUNTER_NUM, 150762306a36Sopenharmony_ci .regs = ksz9477_regs, 150862306a36Sopenharmony_ci .masks = lan937x_masks, 150962306a36Sopenharmony_ci .shifts = lan937x_shifts, 151062306a36Sopenharmony_ci .xmii_ctrl0 = ksz9477_xmii_ctrl0, 151162306a36Sopenharmony_ci .xmii_ctrl1 = ksz9477_xmii_ctrl1, 151262306a36Sopenharmony_ci .supports_mii = {false, false, false, false, 151362306a36Sopenharmony_ci true, true, false, false}, 151462306a36Sopenharmony_ci .supports_rmii = {false, false, false, false, 151562306a36Sopenharmony_ci true, true, false, false}, 151662306a36Sopenharmony_ci .supports_rgmii = {false, false, false, false, 151762306a36Sopenharmony_ci true, true, false, false}, 151862306a36Sopenharmony_ci .internal_phy = {true, true, true, true, 151962306a36Sopenharmony_ci false, false, true, true}, 152062306a36Sopenharmony_ci }, 152162306a36Sopenharmony_ci 152262306a36Sopenharmony_ci [LAN9373] = { 152362306a36Sopenharmony_ci .chip_id = LAN9373_CHIP_ID, 152462306a36Sopenharmony_ci .dev_name = "LAN9373", 152562306a36Sopenharmony_ci .num_vlans = 4096, 152662306a36Sopenharmony_ci .num_alus = 1024, 152762306a36Sopenharmony_ci .num_statics = 256, 152862306a36Sopenharmony_ci .cpu_ports = 0x38, /* can be configured as cpu port */ 152962306a36Sopenharmony_ci .port_cnt = 5, /* total physical port count */ 153062306a36Sopenharmony_ci .port_nirqs = 6, 153162306a36Sopenharmony_ci .num_tx_queues = 8, 153262306a36Sopenharmony_ci .tc_cbs_supported = true, 153362306a36Sopenharmony_ci .tc_ets_supported = true, 153462306a36Sopenharmony_ci .ops = &lan937x_dev_ops, 153562306a36Sopenharmony_ci .mib_names = ksz9477_mib_names, 153662306a36Sopenharmony_ci .mib_cnt = ARRAY_SIZE(ksz9477_mib_names), 153762306a36Sopenharmony_ci .reg_mib_cnt = MIB_COUNTER_NUM, 153862306a36Sopenharmony_ci .regs = ksz9477_regs, 153962306a36Sopenharmony_ci .masks = lan937x_masks, 154062306a36Sopenharmony_ci .shifts = lan937x_shifts, 154162306a36Sopenharmony_ci .xmii_ctrl0 = ksz9477_xmii_ctrl0, 154262306a36Sopenharmony_ci .xmii_ctrl1 = ksz9477_xmii_ctrl1, 154362306a36Sopenharmony_ci .supports_mii = {false, false, false, false, 154462306a36Sopenharmony_ci true, true, false, false}, 154562306a36Sopenharmony_ci .supports_rmii = {false, false, false, false, 154662306a36Sopenharmony_ci true, true, false, false}, 154762306a36Sopenharmony_ci .supports_rgmii = {false, false, false, false, 154862306a36Sopenharmony_ci true, true, false, false}, 154962306a36Sopenharmony_ci .internal_phy = {true, true, true, false, 155062306a36Sopenharmony_ci false, false, true, true}, 155162306a36Sopenharmony_ci }, 155262306a36Sopenharmony_ci 155362306a36Sopenharmony_ci [LAN9374] = { 155462306a36Sopenharmony_ci .chip_id = LAN9374_CHIP_ID, 155562306a36Sopenharmony_ci .dev_name = "LAN9374", 155662306a36Sopenharmony_ci .num_vlans = 4096, 155762306a36Sopenharmony_ci .num_alus = 1024, 155862306a36Sopenharmony_ci .num_statics = 256, 155962306a36Sopenharmony_ci .cpu_ports = 0x30, /* can be configured as cpu port */ 156062306a36Sopenharmony_ci .port_cnt = 8, /* total physical port count */ 156162306a36Sopenharmony_ci .port_nirqs = 6, 156262306a36Sopenharmony_ci .num_tx_queues = 8, 156362306a36Sopenharmony_ci .tc_cbs_supported = true, 156462306a36Sopenharmony_ci .tc_ets_supported = true, 156562306a36Sopenharmony_ci .ops = &lan937x_dev_ops, 156662306a36Sopenharmony_ci .mib_names = ksz9477_mib_names, 156762306a36Sopenharmony_ci .mib_cnt = ARRAY_SIZE(ksz9477_mib_names), 156862306a36Sopenharmony_ci .reg_mib_cnt = MIB_COUNTER_NUM, 156962306a36Sopenharmony_ci .regs = ksz9477_regs, 157062306a36Sopenharmony_ci .masks = lan937x_masks, 157162306a36Sopenharmony_ci .shifts = lan937x_shifts, 157262306a36Sopenharmony_ci .xmii_ctrl0 = ksz9477_xmii_ctrl0, 157362306a36Sopenharmony_ci .xmii_ctrl1 = ksz9477_xmii_ctrl1, 157462306a36Sopenharmony_ci .supports_mii = {false, false, false, false, 157562306a36Sopenharmony_ci true, true, false, false}, 157662306a36Sopenharmony_ci .supports_rmii = {false, false, false, false, 157762306a36Sopenharmony_ci true, true, false, false}, 157862306a36Sopenharmony_ci .supports_rgmii = {false, false, false, false, 157962306a36Sopenharmony_ci true, true, false, false}, 158062306a36Sopenharmony_ci .internal_phy = {true, true, true, true, 158162306a36Sopenharmony_ci false, false, true, true}, 158262306a36Sopenharmony_ci }, 158362306a36Sopenharmony_ci}; 158462306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(ksz_switch_chips); 158562306a36Sopenharmony_ci 158662306a36Sopenharmony_cistatic const struct ksz_chip_data *ksz_lookup_info(unsigned int prod_num) 158762306a36Sopenharmony_ci{ 158862306a36Sopenharmony_ci int i; 158962306a36Sopenharmony_ci 159062306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(ksz_switch_chips); i++) { 159162306a36Sopenharmony_ci const struct ksz_chip_data *chip = &ksz_switch_chips[i]; 159262306a36Sopenharmony_ci 159362306a36Sopenharmony_ci if (chip->chip_id == prod_num) 159462306a36Sopenharmony_ci return chip; 159562306a36Sopenharmony_ci } 159662306a36Sopenharmony_ci 159762306a36Sopenharmony_ci return NULL; 159862306a36Sopenharmony_ci} 159962306a36Sopenharmony_ci 160062306a36Sopenharmony_cistatic int ksz_check_device_id(struct ksz_device *dev) 160162306a36Sopenharmony_ci{ 160262306a36Sopenharmony_ci const struct ksz_chip_data *dt_chip_data; 160362306a36Sopenharmony_ci 160462306a36Sopenharmony_ci dt_chip_data = of_device_get_match_data(dev->dev); 160562306a36Sopenharmony_ci 160662306a36Sopenharmony_ci /* Check for Device Tree and Chip ID */ 160762306a36Sopenharmony_ci if (dt_chip_data->chip_id != dev->chip_id) { 160862306a36Sopenharmony_ci dev_err(dev->dev, 160962306a36Sopenharmony_ci "Device tree specifies chip %s but found %s, please fix it!\n", 161062306a36Sopenharmony_ci dt_chip_data->dev_name, dev->info->dev_name); 161162306a36Sopenharmony_ci return -ENODEV; 161262306a36Sopenharmony_ci } 161362306a36Sopenharmony_ci 161462306a36Sopenharmony_ci return 0; 161562306a36Sopenharmony_ci} 161662306a36Sopenharmony_ci 161762306a36Sopenharmony_cistatic void ksz_phylink_get_caps(struct dsa_switch *ds, int port, 161862306a36Sopenharmony_ci struct phylink_config *config) 161962306a36Sopenharmony_ci{ 162062306a36Sopenharmony_ci struct ksz_device *dev = ds->priv; 162162306a36Sopenharmony_ci 162262306a36Sopenharmony_ci if (dev->info->supports_mii[port]) 162362306a36Sopenharmony_ci __set_bit(PHY_INTERFACE_MODE_MII, config->supported_interfaces); 162462306a36Sopenharmony_ci 162562306a36Sopenharmony_ci if (dev->info->supports_rmii[port]) 162662306a36Sopenharmony_ci __set_bit(PHY_INTERFACE_MODE_RMII, 162762306a36Sopenharmony_ci config->supported_interfaces); 162862306a36Sopenharmony_ci 162962306a36Sopenharmony_ci if (dev->info->supports_rgmii[port]) 163062306a36Sopenharmony_ci phy_interface_set_rgmii(config->supported_interfaces); 163162306a36Sopenharmony_ci 163262306a36Sopenharmony_ci if (dev->info->internal_phy[port]) { 163362306a36Sopenharmony_ci __set_bit(PHY_INTERFACE_MODE_INTERNAL, 163462306a36Sopenharmony_ci config->supported_interfaces); 163562306a36Sopenharmony_ci /* Compatibility for phylib's default interface type when the 163662306a36Sopenharmony_ci * phy-mode property is absent 163762306a36Sopenharmony_ci */ 163862306a36Sopenharmony_ci __set_bit(PHY_INTERFACE_MODE_GMII, 163962306a36Sopenharmony_ci config->supported_interfaces); 164062306a36Sopenharmony_ci } 164162306a36Sopenharmony_ci 164262306a36Sopenharmony_ci if (dev->dev_ops->get_caps) 164362306a36Sopenharmony_ci dev->dev_ops->get_caps(dev, port, config); 164462306a36Sopenharmony_ci} 164562306a36Sopenharmony_ci 164662306a36Sopenharmony_civoid ksz_r_mib_stats64(struct ksz_device *dev, int port) 164762306a36Sopenharmony_ci{ 164862306a36Sopenharmony_ci struct ethtool_pause_stats *pstats; 164962306a36Sopenharmony_ci struct rtnl_link_stats64 *stats; 165062306a36Sopenharmony_ci struct ksz_stats_raw *raw; 165162306a36Sopenharmony_ci struct ksz_port_mib *mib; 165262306a36Sopenharmony_ci 165362306a36Sopenharmony_ci mib = &dev->ports[port].mib; 165462306a36Sopenharmony_ci stats = &mib->stats64; 165562306a36Sopenharmony_ci pstats = &mib->pause_stats; 165662306a36Sopenharmony_ci raw = (struct ksz_stats_raw *)mib->counters; 165762306a36Sopenharmony_ci 165862306a36Sopenharmony_ci spin_lock(&mib->stats64_lock); 165962306a36Sopenharmony_ci 166062306a36Sopenharmony_ci stats->rx_packets = raw->rx_bcast + raw->rx_mcast + raw->rx_ucast + 166162306a36Sopenharmony_ci raw->rx_pause; 166262306a36Sopenharmony_ci stats->tx_packets = raw->tx_bcast + raw->tx_mcast + raw->tx_ucast + 166362306a36Sopenharmony_ci raw->tx_pause; 166462306a36Sopenharmony_ci 166562306a36Sopenharmony_ci /* HW counters are counting bytes + FCS which is not acceptable 166662306a36Sopenharmony_ci * for rtnl_link_stats64 interface 166762306a36Sopenharmony_ci */ 166862306a36Sopenharmony_ci stats->rx_bytes = raw->rx_total - stats->rx_packets * ETH_FCS_LEN; 166962306a36Sopenharmony_ci stats->tx_bytes = raw->tx_total - stats->tx_packets * ETH_FCS_LEN; 167062306a36Sopenharmony_ci 167162306a36Sopenharmony_ci stats->rx_length_errors = raw->rx_undersize + raw->rx_fragments + 167262306a36Sopenharmony_ci raw->rx_oversize; 167362306a36Sopenharmony_ci 167462306a36Sopenharmony_ci stats->rx_crc_errors = raw->rx_crc_err; 167562306a36Sopenharmony_ci stats->rx_frame_errors = raw->rx_align_err; 167662306a36Sopenharmony_ci stats->rx_dropped = raw->rx_discards; 167762306a36Sopenharmony_ci stats->rx_errors = stats->rx_length_errors + stats->rx_crc_errors + 167862306a36Sopenharmony_ci stats->rx_frame_errors + stats->rx_dropped; 167962306a36Sopenharmony_ci 168062306a36Sopenharmony_ci stats->tx_window_errors = raw->tx_late_col; 168162306a36Sopenharmony_ci stats->tx_fifo_errors = raw->tx_discards; 168262306a36Sopenharmony_ci stats->tx_aborted_errors = raw->tx_exc_col; 168362306a36Sopenharmony_ci stats->tx_errors = stats->tx_window_errors + stats->tx_fifo_errors + 168462306a36Sopenharmony_ci stats->tx_aborted_errors; 168562306a36Sopenharmony_ci 168662306a36Sopenharmony_ci stats->multicast = raw->rx_mcast; 168762306a36Sopenharmony_ci stats->collisions = raw->tx_total_col; 168862306a36Sopenharmony_ci 168962306a36Sopenharmony_ci pstats->tx_pause_frames = raw->tx_pause; 169062306a36Sopenharmony_ci pstats->rx_pause_frames = raw->rx_pause; 169162306a36Sopenharmony_ci 169262306a36Sopenharmony_ci spin_unlock(&mib->stats64_lock); 169362306a36Sopenharmony_ci} 169462306a36Sopenharmony_ci 169562306a36Sopenharmony_civoid ksz88xx_r_mib_stats64(struct ksz_device *dev, int port) 169662306a36Sopenharmony_ci{ 169762306a36Sopenharmony_ci struct ethtool_pause_stats *pstats; 169862306a36Sopenharmony_ci struct rtnl_link_stats64 *stats; 169962306a36Sopenharmony_ci struct ksz88xx_stats_raw *raw; 170062306a36Sopenharmony_ci struct ksz_port_mib *mib; 170162306a36Sopenharmony_ci 170262306a36Sopenharmony_ci mib = &dev->ports[port].mib; 170362306a36Sopenharmony_ci stats = &mib->stats64; 170462306a36Sopenharmony_ci pstats = &mib->pause_stats; 170562306a36Sopenharmony_ci raw = (struct ksz88xx_stats_raw *)mib->counters; 170662306a36Sopenharmony_ci 170762306a36Sopenharmony_ci spin_lock(&mib->stats64_lock); 170862306a36Sopenharmony_ci 170962306a36Sopenharmony_ci stats->rx_packets = raw->rx_bcast + raw->rx_mcast + raw->rx_ucast + 171062306a36Sopenharmony_ci raw->rx_pause; 171162306a36Sopenharmony_ci stats->tx_packets = raw->tx_bcast + raw->tx_mcast + raw->tx_ucast + 171262306a36Sopenharmony_ci raw->tx_pause; 171362306a36Sopenharmony_ci 171462306a36Sopenharmony_ci /* HW counters are counting bytes + FCS which is not acceptable 171562306a36Sopenharmony_ci * for rtnl_link_stats64 interface 171662306a36Sopenharmony_ci */ 171762306a36Sopenharmony_ci stats->rx_bytes = raw->rx + raw->rx_hi - stats->rx_packets * ETH_FCS_LEN; 171862306a36Sopenharmony_ci stats->tx_bytes = raw->tx + raw->tx_hi - stats->tx_packets * ETH_FCS_LEN; 171962306a36Sopenharmony_ci 172062306a36Sopenharmony_ci stats->rx_length_errors = raw->rx_undersize + raw->rx_fragments + 172162306a36Sopenharmony_ci raw->rx_oversize; 172262306a36Sopenharmony_ci 172362306a36Sopenharmony_ci stats->rx_crc_errors = raw->rx_crc_err; 172462306a36Sopenharmony_ci stats->rx_frame_errors = raw->rx_align_err; 172562306a36Sopenharmony_ci stats->rx_dropped = raw->rx_discards; 172662306a36Sopenharmony_ci stats->rx_errors = stats->rx_length_errors + stats->rx_crc_errors + 172762306a36Sopenharmony_ci stats->rx_frame_errors + stats->rx_dropped; 172862306a36Sopenharmony_ci 172962306a36Sopenharmony_ci stats->tx_window_errors = raw->tx_late_col; 173062306a36Sopenharmony_ci stats->tx_fifo_errors = raw->tx_discards; 173162306a36Sopenharmony_ci stats->tx_aborted_errors = raw->tx_exc_col; 173262306a36Sopenharmony_ci stats->tx_errors = stats->tx_window_errors + stats->tx_fifo_errors + 173362306a36Sopenharmony_ci stats->tx_aborted_errors; 173462306a36Sopenharmony_ci 173562306a36Sopenharmony_ci stats->multicast = raw->rx_mcast; 173662306a36Sopenharmony_ci stats->collisions = raw->tx_total_col; 173762306a36Sopenharmony_ci 173862306a36Sopenharmony_ci pstats->tx_pause_frames = raw->tx_pause; 173962306a36Sopenharmony_ci pstats->rx_pause_frames = raw->rx_pause; 174062306a36Sopenharmony_ci 174162306a36Sopenharmony_ci spin_unlock(&mib->stats64_lock); 174262306a36Sopenharmony_ci} 174362306a36Sopenharmony_ci 174462306a36Sopenharmony_cistatic void ksz_get_stats64(struct dsa_switch *ds, int port, 174562306a36Sopenharmony_ci struct rtnl_link_stats64 *s) 174662306a36Sopenharmony_ci{ 174762306a36Sopenharmony_ci struct ksz_device *dev = ds->priv; 174862306a36Sopenharmony_ci struct ksz_port_mib *mib; 174962306a36Sopenharmony_ci 175062306a36Sopenharmony_ci mib = &dev->ports[port].mib; 175162306a36Sopenharmony_ci 175262306a36Sopenharmony_ci spin_lock(&mib->stats64_lock); 175362306a36Sopenharmony_ci memcpy(s, &mib->stats64, sizeof(*s)); 175462306a36Sopenharmony_ci spin_unlock(&mib->stats64_lock); 175562306a36Sopenharmony_ci} 175662306a36Sopenharmony_ci 175762306a36Sopenharmony_cistatic void ksz_get_pause_stats(struct dsa_switch *ds, int port, 175862306a36Sopenharmony_ci struct ethtool_pause_stats *pause_stats) 175962306a36Sopenharmony_ci{ 176062306a36Sopenharmony_ci struct ksz_device *dev = ds->priv; 176162306a36Sopenharmony_ci struct ksz_port_mib *mib; 176262306a36Sopenharmony_ci 176362306a36Sopenharmony_ci mib = &dev->ports[port].mib; 176462306a36Sopenharmony_ci 176562306a36Sopenharmony_ci spin_lock(&mib->stats64_lock); 176662306a36Sopenharmony_ci memcpy(pause_stats, &mib->pause_stats, sizeof(*pause_stats)); 176762306a36Sopenharmony_ci spin_unlock(&mib->stats64_lock); 176862306a36Sopenharmony_ci} 176962306a36Sopenharmony_ci 177062306a36Sopenharmony_cistatic void ksz_get_strings(struct dsa_switch *ds, int port, 177162306a36Sopenharmony_ci u32 stringset, uint8_t *buf) 177262306a36Sopenharmony_ci{ 177362306a36Sopenharmony_ci struct ksz_device *dev = ds->priv; 177462306a36Sopenharmony_ci int i; 177562306a36Sopenharmony_ci 177662306a36Sopenharmony_ci if (stringset != ETH_SS_STATS) 177762306a36Sopenharmony_ci return; 177862306a36Sopenharmony_ci 177962306a36Sopenharmony_ci for (i = 0; i < dev->info->mib_cnt; i++) { 178062306a36Sopenharmony_ci memcpy(buf + i * ETH_GSTRING_LEN, 178162306a36Sopenharmony_ci dev->info->mib_names[i].string, ETH_GSTRING_LEN); 178262306a36Sopenharmony_ci } 178362306a36Sopenharmony_ci} 178462306a36Sopenharmony_ci 178562306a36Sopenharmony_cistatic void ksz_update_port_member(struct ksz_device *dev, int port) 178662306a36Sopenharmony_ci{ 178762306a36Sopenharmony_ci struct ksz_port *p = &dev->ports[port]; 178862306a36Sopenharmony_ci struct dsa_switch *ds = dev->ds; 178962306a36Sopenharmony_ci u8 port_member = 0, cpu_port; 179062306a36Sopenharmony_ci const struct dsa_port *dp; 179162306a36Sopenharmony_ci int i, j; 179262306a36Sopenharmony_ci 179362306a36Sopenharmony_ci if (!dsa_is_user_port(ds, port)) 179462306a36Sopenharmony_ci return; 179562306a36Sopenharmony_ci 179662306a36Sopenharmony_ci dp = dsa_to_port(ds, port); 179762306a36Sopenharmony_ci cpu_port = BIT(dsa_upstream_port(ds, port)); 179862306a36Sopenharmony_ci 179962306a36Sopenharmony_ci for (i = 0; i < ds->num_ports; i++) { 180062306a36Sopenharmony_ci const struct dsa_port *other_dp = dsa_to_port(ds, i); 180162306a36Sopenharmony_ci struct ksz_port *other_p = &dev->ports[i]; 180262306a36Sopenharmony_ci u8 val = 0; 180362306a36Sopenharmony_ci 180462306a36Sopenharmony_ci if (!dsa_is_user_port(ds, i)) 180562306a36Sopenharmony_ci continue; 180662306a36Sopenharmony_ci if (port == i) 180762306a36Sopenharmony_ci continue; 180862306a36Sopenharmony_ci if (!dsa_port_bridge_same(dp, other_dp)) 180962306a36Sopenharmony_ci continue; 181062306a36Sopenharmony_ci if (other_p->stp_state != BR_STATE_FORWARDING) 181162306a36Sopenharmony_ci continue; 181262306a36Sopenharmony_ci 181362306a36Sopenharmony_ci if (p->stp_state == BR_STATE_FORWARDING) { 181462306a36Sopenharmony_ci val |= BIT(port); 181562306a36Sopenharmony_ci port_member |= BIT(i); 181662306a36Sopenharmony_ci } 181762306a36Sopenharmony_ci 181862306a36Sopenharmony_ci /* Retain port [i]'s relationship to other ports than [port] */ 181962306a36Sopenharmony_ci for (j = 0; j < ds->num_ports; j++) { 182062306a36Sopenharmony_ci const struct dsa_port *third_dp; 182162306a36Sopenharmony_ci struct ksz_port *third_p; 182262306a36Sopenharmony_ci 182362306a36Sopenharmony_ci if (j == i) 182462306a36Sopenharmony_ci continue; 182562306a36Sopenharmony_ci if (j == port) 182662306a36Sopenharmony_ci continue; 182762306a36Sopenharmony_ci if (!dsa_is_user_port(ds, j)) 182862306a36Sopenharmony_ci continue; 182962306a36Sopenharmony_ci third_p = &dev->ports[j]; 183062306a36Sopenharmony_ci if (third_p->stp_state != BR_STATE_FORWARDING) 183162306a36Sopenharmony_ci continue; 183262306a36Sopenharmony_ci third_dp = dsa_to_port(ds, j); 183362306a36Sopenharmony_ci if (dsa_port_bridge_same(other_dp, third_dp)) 183462306a36Sopenharmony_ci val |= BIT(j); 183562306a36Sopenharmony_ci } 183662306a36Sopenharmony_ci 183762306a36Sopenharmony_ci dev->dev_ops->cfg_port_member(dev, i, val | cpu_port); 183862306a36Sopenharmony_ci } 183962306a36Sopenharmony_ci 184062306a36Sopenharmony_ci dev->dev_ops->cfg_port_member(dev, port, port_member | cpu_port); 184162306a36Sopenharmony_ci} 184262306a36Sopenharmony_ci 184362306a36Sopenharmony_cistatic int ksz_sw_mdio_read(struct mii_bus *bus, int addr, int regnum) 184462306a36Sopenharmony_ci{ 184562306a36Sopenharmony_ci struct ksz_device *dev = bus->priv; 184662306a36Sopenharmony_ci u16 val; 184762306a36Sopenharmony_ci int ret; 184862306a36Sopenharmony_ci 184962306a36Sopenharmony_ci ret = dev->dev_ops->r_phy(dev, addr, regnum, &val); 185062306a36Sopenharmony_ci if (ret < 0) 185162306a36Sopenharmony_ci return ret; 185262306a36Sopenharmony_ci 185362306a36Sopenharmony_ci return val; 185462306a36Sopenharmony_ci} 185562306a36Sopenharmony_ci 185662306a36Sopenharmony_cistatic int ksz_sw_mdio_write(struct mii_bus *bus, int addr, int regnum, 185762306a36Sopenharmony_ci u16 val) 185862306a36Sopenharmony_ci{ 185962306a36Sopenharmony_ci struct ksz_device *dev = bus->priv; 186062306a36Sopenharmony_ci 186162306a36Sopenharmony_ci return dev->dev_ops->w_phy(dev, addr, regnum, val); 186262306a36Sopenharmony_ci} 186362306a36Sopenharmony_ci 186462306a36Sopenharmony_cistatic int ksz_irq_phy_setup(struct ksz_device *dev) 186562306a36Sopenharmony_ci{ 186662306a36Sopenharmony_ci struct dsa_switch *ds = dev->ds; 186762306a36Sopenharmony_ci int phy; 186862306a36Sopenharmony_ci int irq; 186962306a36Sopenharmony_ci int ret; 187062306a36Sopenharmony_ci 187162306a36Sopenharmony_ci for (phy = 0; phy < KSZ_MAX_NUM_PORTS; phy++) { 187262306a36Sopenharmony_ci if (BIT(phy) & ds->phys_mii_mask) { 187362306a36Sopenharmony_ci irq = irq_find_mapping(dev->ports[phy].pirq.domain, 187462306a36Sopenharmony_ci PORT_SRC_PHY_INT); 187562306a36Sopenharmony_ci if (irq < 0) { 187662306a36Sopenharmony_ci ret = irq; 187762306a36Sopenharmony_ci goto out; 187862306a36Sopenharmony_ci } 187962306a36Sopenharmony_ci ds->slave_mii_bus->irq[phy] = irq; 188062306a36Sopenharmony_ci } 188162306a36Sopenharmony_ci } 188262306a36Sopenharmony_ci return 0; 188362306a36Sopenharmony_ciout: 188462306a36Sopenharmony_ci while (phy--) 188562306a36Sopenharmony_ci if (BIT(phy) & ds->phys_mii_mask) 188662306a36Sopenharmony_ci irq_dispose_mapping(ds->slave_mii_bus->irq[phy]); 188762306a36Sopenharmony_ci 188862306a36Sopenharmony_ci return ret; 188962306a36Sopenharmony_ci} 189062306a36Sopenharmony_ci 189162306a36Sopenharmony_cistatic void ksz_irq_phy_free(struct ksz_device *dev) 189262306a36Sopenharmony_ci{ 189362306a36Sopenharmony_ci struct dsa_switch *ds = dev->ds; 189462306a36Sopenharmony_ci int phy; 189562306a36Sopenharmony_ci 189662306a36Sopenharmony_ci for (phy = 0; phy < KSZ_MAX_NUM_PORTS; phy++) 189762306a36Sopenharmony_ci if (BIT(phy) & ds->phys_mii_mask) 189862306a36Sopenharmony_ci irq_dispose_mapping(ds->slave_mii_bus->irq[phy]); 189962306a36Sopenharmony_ci} 190062306a36Sopenharmony_ci 190162306a36Sopenharmony_cistatic int ksz_mdio_register(struct ksz_device *dev) 190262306a36Sopenharmony_ci{ 190362306a36Sopenharmony_ci struct dsa_switch *ds = dev->ds; 190462306a36Sopenharmony_ci struct device_node *mdio_np; 190562306a36Sopenharmony_ci struct mii_bus *bus; 190662306a36Sopenharmony_ci int ret; 190762306a36Sopenharmony_ci 190862306a36Sopenharmony_ci mdio_np = of_get_child_by_name(dev->dev->of_node, "mdio"); 190962306a36Sopenharmony_ci if (!mdio_np) 191062306a36Sopenharmony_ci return 0; 191162306a36Sopenharmony_ci 191262306a36Sopenharmony_ci bus = devm_mdiobus_alloc(ds->dev); 191362306a36Sopenharmony_ci if (!bus) { 191462306a36Sopenharmony_ci of_node_put(mdio_np); 191562306a36Sopenharmony_ci return -ENOMEM; 191662306a36Sopenharmony_ci } 191762306a36Sopenharmony_ci 191862306a36Sopenharmony_ci bus->priv = dev; 191962306a36Sopenharmony_ci bus->read = ksz_sw_mdio_read; 192062306a36Sopenharmony_ci bus->write = ksz_sw_mdio_write; 192162306a36Sopenharmony_ci bus->name = "ksz slave smi"; 192262306a36Sopenharmony_ci snprintf(bus->id, MII_BUS_ID_SIZE, "SMI-%d", ds->index); 192362306a36Sopenharmony_ci bus->parent = ds->dev; 192462306a36Sopenharmony_ci bus->phy_mask = ~ds->phys_mii_mask; 192562306a36Sopenharmony_ci 192662306a36Sopenharmony_ci ds->slave_mii_bus = bus; 192762306a36Sopenharmony_ci 192862306a36Sopenharmony_ci if (dev->irq > 0) { 192962306a36Sopenharmony_ci ret = ksz_irq_phy_setup(dev); 193062306a36Sopenharmony_ci if (ret) { 193162306a36Sopenharmony_ci of_node_put(mdio_np); 193262306a36Sopenharmony_ci return ret; 193362306a36Sopenharmony_ci } 193462306a36Sopenharmony_ci } 193562306a36Sopenharmony_ci 193662306a36Sopenharmony_ci ret = devm_of_mdiobus_register(ds->dev, bus, mdio_np); 193762306a36Sopenharmony_ci if (ret) { 193862306a36Sopenharmony_ci dev_err(ds->dev, "unable to register MDIO bus %s\n", 193962306a36Sopenharmony_ci bus->id); 194062306a36Sopenharmony_ci if (dev->irq > 0) 194162306a36Sopenharmony_ci ksz_irq_phy_free(dev); 194262306a36Sopenharmony_ci } 194362306a36Sopenharmony_ci 194462306a36Sopenharmony_ci of_node_put(mdio_np); 194562306a36Sopenharmony_ci 194662306a36Sopenharmony_ci return ret; 194762306a36Sopenharmony_ci} 194862306a36Sopenharmony_ci 194962306a36Sopenharmony_cistatic void ksz_irq_mask(struct irq_data *d) 195062306a36Sopenharmony_ci{ 195162306a36Sopenharmony_ci struct ksz_irq *kirq = irq_data_get_irq_chip_data(d); 195262306a36Sopenharmony_ci 195362306a36Sopenharmony_ci kirq->masked |= BIT(d->hwirq); 195462306a36Sopenharmony_ci} 195562306a36Sopenharmony_ci 195662306a36Sopenharmony_cistatic void ksz_irq_unmask(struct irq_data *d) 195762306a36Sopenharmony_ci{ 195862306a36Sopenharmony_ci struct ksz_irq *kirq = irq_data_get_irq_chip_data(d); 195962306a36Sopenharmony_ci 196062306a36Sopenharmony_ci kirq->masked &= ~BIT(d->hwirq); 196162306a36Sopenharmony_ci} 196262306a36Sopenharmony_ci 196362306a36Sopenharmony_cistatic void ksz_irq_bus_lock(struct irq_data *d) 196462306a36Sopenharmony_ci{ 196562306a36Sopenharmony_ci struct ksz_irq *kirq = irq_data_get_irq_chip_data(d); 196662306a36Sopenharmony_ci 196762306a36Sopenharmony_ci mutex_lock(&kirq->dev->lock_irq); 196862306a36Sopenharmony_ci} 196962306a36Sopenharmony_ci 197062306a36Sopenharmony_cistatic void ksz_irq_bus_sync_unlock(struct irq_data *d) 197162306a36Sopenharmony_ci{ 197262306a36Sopenharmony_ci struct ksz_irq *kirq = irq_data_get_irq_chip_data(d); 197362306a36Sopenharmony_ci struct ksz_device *dev = kirq->dev; 197462306a36Sopenharmony_ci int ret; 197562306a36Sopenharmony_ci 197662306a36Sopenharmony_ci ret = ksz_write32(dev, kirq->reg_mask, kirq->masked); 197762306a36Sopenharmony_ci if (ret) 197862306a36Sopenharmony_ci dev_err(dev->dev, "failed to change IRQ mask\n"); 197962306a36Sopenharmony_ci 198062306a36Sopenharmony_ci mutex_unlock(&dev->lock_irq); 198162306a36Sopenharmony_ci} 198262306a36Sopenharmony_ci 198362306a36Sopenharmony_cistatic const struct irq_chip ksz_irq_chip = { 198462306a36Sopenharmony_ci .name = "ksz-irq", 198562306a36Sopenharmony_ci .irq_mask = ksz_irq_mask, 198662306a36Sopenharmony_ci .irq_unmask = ksz_irq_unmask, 198762306a36Sopenharmony_ci .irq_bus_lock = ksz_irq_bus_lock, 198862306a36Sopenharmony_ci .irq_bus_sync_unlock = ksz_irq_bus_sync_unlock, 198962306a36Sopenharmony_ci}; 199062306a36Sopenharmony_ci 199162306a36Sopenharmony_cistatic int ksz_irq_domain_map(struct irq_domain *d, 199262306a36Sopenharmony_ci unsigned int irq, irq_hw_number_t hwirq) 199362306a36Sopenharmony_ci{ 199462306a36Sopenharmony_ci irq_set_chip_data(irq, d->host_data); 199562306a36Sopenharmony_ci irq_set_chip_and_handler(irq, &ksz_irq_chip, handle_level_irq); 199662306a36Sopenharmony_ci irq_set_noprobe(irq); 199762306a36Sopenharmony_ci 199862306a36Sopenharmony_ci return 0; 199962306a36Sopenharmony_ci} 200062306a36Sopenharmony_ci 200162306a36Sopenharmony_cistatic const struct irq_domain_ops ksz_irq_domain_ops = { 200262306a36Sopenharmony_ci .map = ksz_irq_domain_map, 200362306a36Sopenharmony_ci .xlate = irq_domain_xlate_twocell, 200462306a36Sopenharmony_ci}; 200562306a36Sopenharmony_ci 200662306a36Sopenharmony_cistatic void ksz_irq_free(struct ksz_irq *kirq) 200762306a36Sopenharmony_ci{ 200862306a36Sopenharmony_ci int irq, virq; 200962306a36Sopenharmony_ci 201062306a36Sopenharmony_ci free_irq(kirq->irq_num, kirq); 201162306a36Sopenharmony_ci 201262306a36Sopenharmony_ci for (irq = 0; irq < kirq->nirqs; irq++) { 201362306a36Sopenharmony_ci virq = irq_find_mapping(kirq->domain, irq); 201462306a36Sopenharmony_ci irq_dispose_mapping(virq); 201562306a36Sopenharmony_ci } 201662306a36Sopenharmony_ci 201762306a36Sopenharmony_ci irq_domain_remove(kirq->domain); 201862306a36Sopenharmony_ci} 201962306a36Sopenharmony_ci 202062306a36Sopenharmony_cistatic irqreturn_t ksz_irq_thread_fn(int irq, void *dev_id) 202162306a36Sopenharmony_ci{ 202262306a36Sopenharmony_ci struct ksz_irq *kirq = dev_id; 202362306a36Sopenharmony_ci unsigned int nhandled = 0; 202462306a36Sopenharmony_ci struct ksz_device *dev; 202562306a36Sopenharmony_ci unsigned int sub_irq; 202662306a36Sopenharmony_ci u8 data; 202762306a36Sopenharmony_ci int ret; 202862306a36Sopenharmony_ci u8 n; 202962306a36Sopenharmony_ci 203062306a36Sopenharmony_ci dev = kirq->dev; 203162306a36Sopenharmony_ci 203262306a36Sopenharmony_ci /* Read interrupt status register */ 203362306a36Sopenharmony_ci ret = ksz_read8(dev, kirq->reg_status, &data); 203462306a36Sopenharmony_ci if (ret) 203562306a36Sopenharmony_ci goto out; 203662306a36Sopenharmony_ci 203762306a36Sopenharmony_ci for (n = 0; n < kirq->nirqs; ++n) { 203862306a36Sopenharmony_ci if (data & BIT(n)) { 203962306a36Sopenharmony_ci sub_irq = irq_find_mapping(kirq->domain, n); 204062306a36Sopenharmony_ci handle_nested_irq(sub_irq); 204162306a36Sopenharmony_ci ++nhandled; 204262306a36Sopenharmony_ci } 204362306a36Sopenharmony_ci } 204462306a36Sopenharmony_ciout: 204562306a36Sopenharmony_ci return (nhandled > 0 ? IRQ_HANDLED : IRQ_NONE); 204662306a36Sopenharmony_ci} 204762306a36Sopenharmony_ci 204862306a36Sopenharmony_cistatic int ksz_irq_common_setup(struct ksz_device *dev, struct ksz_irq *kirq) 204962306a36Sopenharmony_ci{ 205062306a36Sopenharmony_ci int ret, n; 205162306a36Sopenharmony_ci 205262306a36Sopenharmony_ci kirq->dev = dev; 205362306a36Sopenharmony_ci kirq->masked = ~0; 205462306a36Sopenharmony_ci 205562306a36Sopenharmony_ci kirq->domain = irq_domain_add_simple(dev->dev->of_node, kirq->nirqs, 0, 205662306a36Sopenharmony_ci &ksz_irq_domain_ops, kirq); 205762306a36Sopenharmony_ci if (!kirq->domain) 205862306a36Sopenharmony_ci return -ENOMEM; 205962306a36Sopenharmony_ci 206062306a36Sopenharmony_ci for (n = 0; n < kirq->nirqs; n++) 206162306a36Sopenharmony_ci irq_create_mapping(kirq->domain, n); 206262306a36Sopenharmony_ci 206362306a36Sopenharmony_ci ret = request_threaded_irq(kirq->irq_num, NULL, ksz_irq_thread_fn, 206462306a36Sopenharmony_ci IRQF_ONESHOT, kirq->name, kirq); 206562306a36Sopenharmony_ci if (ret) 206662306a36Sopenharmony_ci goto out; 206762306a36Sopenharmony_ci 206862306a36Sopenharmony_ci return 0; 206962306a36Sopenharmony_ci 207062306a36Sopenharmony_ciout: 207162306a36Sopenharmony_ci ksz_irq_free(kirq); 207262306a36Sopenharmony_ci 207362306a36Sopenharmony_ci return ret; 207462306a36Sopenharmony_ci} 207562306a36Sopenharmony_ci 207662306a36Sopenharmony_cistatic int ksz_girq_setup(struct ksz_device *dev) 207762306a36Sopenharmony_ci{ 207862306a36Sopenharmony_ci struct ksz_irq *girq = &dev->girq; 207962306a36Sopenharmony_ci 208062306a36Sopenharmony_ci girq->nirqs = dev->info->port_cnt; 208162306a36Sopenharmony_ci girq->reg_mask = REG_SW_PORT_INT_MASK__1; 208262306a36Sopenharmony_ci girq->reg_status = REG_SW_PORT_INT_STATUS__1; 208362306a36Sopenharmony_ci snprintf(girq->name, sizeof(girq->name), "global_port_irq"); 208462306a36Sopenharmony_ci 208562306a36Sopenharmony_ci girq->irq_num = dev->irq; 208662306a36Sopenharmony_ci 208762306a36Sopenharmony_ci return ksz_irq_common_setup(dev, girq); 208862306a36Sopenharmony_ci} 208962306a36Sopenharmony_ci 209062306a36Sopenharmony_cistatic int ksz_pirq_setup(struct ksz_device *dev, u8 p) 209162306a36Sopenharmony_ci{ 209262306a36Sopenharmony_ci struct ksz_irq *pirq = &dev->ports[p].pirq; 209362306a36Sopenharmony_ci 209462306a36Sopenharmony_ci pirq->nirqs = dev->info->port_nirqs; 209562306a36Sopenharmony_ci pirq->reg_mask = dev->dev_ops->get_port_addr(p, REG_PORT_INT_MASK); 209662306a36Sopenharmony_ci pirq->reg_status = dev->dev_ops->get_port_addr(p, REG_PORT_INT_STATUS); 209762306a36Sopenharmony_ci snprintf(pirq->name, sizeof(pirq->name), "port_irq-%d", p); 209862306a36Sopenharmony_ci 209962306a36Sopenharmony_ci pirq->irq_num = irq_find_mapping(dev->girq.domain, p); 210062306a36Sopenharmony_ci if (pirq->irq_num < 0) 210162306a36Sopenharmony_ci return pirq->irq_num; 210262306a36Sopenharmony_ci 210362306a36Sopenharmony_ci return ksz_irq_common_setup(dev, pirq); 210462306a36Sopenharmony_ci} 210562306a36Sopenharmony_ci 210662306a36Sopenharmony_cistatic int ksz_setup(struct dsa_switch *ds) 210762306a36Sopenharmony_ci{ 210862306a36Sopenharmony_ci struct ksz_device *dev = ds->priv; 210962306a36Sopenharmony_ci struct dsa_port *dp; 211062306a36Sopenharmony_ci struct ksz_port *p; 211162306a36Sopenharmony_ci const u16 *regs; 211262306a36Sopenharmony_ci int ret; 211362306a36Sopenharmony_ci 211462306a36Sopenharmony_ci regs = dev->info->regs; 211562306a36Sopenharmony_ci 211662306a36Sopenharmony_ci dev->vlan_cache = devm_kcalloc(dev->dev, sizeof(struct vlan_table), 211762306a36Sopenharmony_ci dev->info->num_vlans, GFP_KERNEL); 211862306a36Sopenharmony_ci if (!dev->vlan_cache) 211962306a36Sopenharmony_ci return -ENOMEM; 212062306a36Sopenharmony_ci 212162306a36Sopenharmony_ci ret = dev->dev_ops->reset(dev); 212262306a36Sopenharmony_ci if (ret) { 212362306a36Sopenharmony_ci dev_err(ds->dev, "failed to reset switch\n"); 212462306a36Sopenharmony_ci return ret; 212562306a36Sopenharmony_ci } 212662306a36Sopenharmony_ci 212762306a36Sopenharmony_ci /* set broadcast storm protection 10% rate */ 212862306a36Sopenharmony_ci regmap_update_bits(ksz_regmap_16(dev), regs[S_BROADCAST_CTRL], 212962306a36Sopenharmony_ci BROADCAST_STORM_RATE, 213062306a36Sopenharmony_ci (BROADCAST_STORM_VALUE * 213162306a36Sopenharmony_ci BROADCAST_STORM_PROT_RATE) / 100); 213262306a36Sopenharmony_ci 213362306a36Sopenharmony_ci dev->dev_ops->config_cpu_port(ds); 213462306a36Sopenharmony_ci 213562306a36Sopenharmony_ci dev->dev_ops->enable_stp_addr(dev); 213662306a36Sopenharmony_ci 213762306a36Sopenharmony_ci ds->num_tx_queues = dev->info->num_tx_queues; 213862306a36Sopenharmony_ci 213962306a36Sopenharmony_ci regmap_update_bits(ksz_regmap_8(dev), regs[S_MULTICAST_CTRL], 214062306a36Sopenharmony_ci MULTICAST_STORM_DISABLE, MULTICAST_STORM_DISABLE); 214162306a36Sopenharmony_ci 214262306a36Sopenharmony_ci ksz_init_mib_timer(dev); 214362306a36Sopenharmony_ci 214462306a36Sopenharmony_ci ds->configure_vlan_while_not_filtering = false; 214562306a36Sopenharmony_ci 214662306a36Sopenharmony_ci if (dev->dev_ops->setup) { 214762306a36Sopenharmony_ci ret = dev->dev_ops->setup(ds); 214862306a36Sopenharmony_ci if (ret) 214962306a36Sopenharmony_ci return ret; 215062306a36Sopenharmony_ci } 215162306a36Sopenharmony_ci 215262306a36Sopenharmony_ci /* Start with learning disabled on standalone user ports, and enabled 215362306a36Sopenharmony_ci * on the CPU port. In lack of other finer mechanisms, learning on the 215462306a36Sopenharmony_ci * CPU port will avoid flooding bridge local addresses on the network 215562306a36Sopenharmony_ci * in some cases. 215662306a36Sopenharmony_ci */ 215762306a36Sopenharmony_ci p = &dev->ports[dev->cpu_port]; 215862306a36Sopenharmony_ci p->learning = true; 215962306a36Sopenharmony_ci 216062306a36Sopenharmony_ci if (dev->irq > 0) { 216162306a36Sopenharmony_ci ret = ksz_girq_setup(dev); 216262306a36Sopenharmony_ci if (ret) 216362306a36Sopenharmony_ci return ret; 216462306a36Sopenharmony_ci 216562306a36Sopenharmony_ci dsa_switch_for_each_user_port(dp, dev->ds) { 216662306a36Sopenharmony_ci ret = ksz_pirq_setup(dev, dp->index); 216762306a36Sopenharmony_ci if (ret) 216862306a36Sopenharmony_ci goto out_girq; 216962306a36Sopenharmony_ci 217062306a36Sopenharmony_ci ret = ksz_ptp_irq_setup(ds, dp->index); 217162306a36Sopenharmony_ci if (ret) 217262306a36Sopenharmony_ci goto out_pirq; 217362306a36Sopenharmony_ci } 217462306a36Sopenharmony_ci } 217562306a36Sopenharmony_ci 217662306a36Sopenharmony_ci ret = ksz_ptp_clock_register(ds); 217762306a36Sopenharmony_ci if (ret) { 217862306a36Sopenharmony_ci dev_err(dev->dev, "Failed to register PTP clock: %d\n", ret); 217962306a36Sopenharmony_ci goto out_ptpirq; 218062306a36Sopenharmony_ci } 218162306a36Sopenharmony_ci 218262306a36Sopenharmony_ci ret = ksz_mdio_register(dev); 218362306a36Sopenharmony_ci if (ret < 0) { 218462306a36Sopenharmony_ci dev_err(dev->dev, "failed to register the mdio"); 218562306a36Sopenharmony_ci goto out_ptp_clock_unregister; 218662306a36Sopenharmony_ci } 218762306a36Sopenharmony_ci 218862306a36Sopenharmony_ci /* start switch */ 218962306a36Sopenharmony_ci regmap_update_bits(ksz_regmap_8(dev), regs[S_START_CTRL], 219062306a36Sopenharmony_ci SW_START, SW_START); 219162306a36Sopenharmony_ci 219262306a36Sopenharmony_ci return 0; 219362306a36Sopenharmony_ci 219462306a36Sopenharmony_ciout_ptp_clock_unregister: 219562306a36Sopenharmony_ci ksz_ptp_clock_unregister(ds); 219662306a36Sopenharmony_ciout_ptpirq: 219762306a36Sopenharmony_ci if (dev->irq > 0) 219862306a36Sopenharmony_ci dsa_switch_for_each_user_port(dp, dev->ds) 219962306a36Sopenharmony_ci ksz_ptp_irq_free(ds, dp->index); 220062306a36Sopenharmony_ciout_pirq: 220162306a36Sopenharmony_ci if (dev->irq > 0) 220262306a36Sopenharmony_ci dsa_switch_for_each_user_port(dp, dev->ds) 220362306a36Sopenharmony_ci ksz_irq_free(&dev->ports[dp->index].pirq); 220462306a36Sopenharmony_ciout_girq: 220562306a36Sopenharmony_ci if (dev->irq > 0) 220662306a36Sopenharmony_ci ksz_irq_free(&dev->girq); 220762306a36Sopenharmony_ci 220862306a36Sopenharmony_ci return ret; 220962306a36Sopenharmony_ci} 221062306a36Sopenharmony_ci 221162306a36Sopenharmony_cistatic void ksz_teardown(struct dsa_switch *ds) 221262306a36Sopenharmony_ci{ 221362306a36Sopenharmony_ci struct ksz_device *dev = ds->priv; 221462306a36Sopenharmony_ci struct dsa_port *dp; 221562306a36Sopenharmony_ci 221662306a36Sopenharmony_ci ksz_ptp_clock_unregister(ds); 221762306a36Sopenharmony_ci 221862306a36Sopenharmony_ci if (dev->irq > 0) { 221962306a36Sopenharmony_ci dsa_switch_for_each_user_port(dp, dev->ds) { 222062306a36Sopenharmony_ci ksz_ptp_irq_free(ds, dp->index); 222162306a36Sopenharmony_ci 222262306a36Sopenharmony_ci ksz_irq_free(&dev->ports[dp->index].pirq); 222362306a36Sopenharmony_ci } 222462306a36Sopenharmony_ci 222562306a36Sopenharmony_ci ksz_irq_free(&dev->girq); 222662306a36Sopenharmony_ci } 222762306a36Sopenharmony_ci 222862306a36Sopenharmony_ci if (dev->dev_ops->teardown) 222962306a36Sopenharmony_ci dev->dev_ops->teardown(ds); 223062306a36Sopenharmony_ci} 223162306a36Sopenharmony_ci 223262306a36Sopenharmony_cistatic void port_r_cnt(struct ksz_device *dev, int port) 223362306a36Sopenharmony_ci{ 223462306a36Sopenharmony_ci struct ksz_port_mib *mib = &dev->ports[port].mib; 223562306a36Sopenharmony_ci u64 *dropped; 223662306a36Sopenharmony_ci 223762306a36Sopenharmony_ci /* Some ports may not have MIB counters before SWITCH_COUNTER_NUM. */ 223862306a36Sopenharmony_ci while (mib->cnt_ptr < dev->info->reg_mib_cnt) { 223962306a36Sopenharmony_ci dev->dev_ops->r_mib_cnt(dev, port, mib->cnt_ptr, 224062306a36Sopenharmony_ci &mib->counters[mib->cnt_ptr]); 224162306a36Sopenharmony_ci ++mib->cnt_ptr; 224262306a36Sopenharmony_ci } 224362306a36Sopenharmony_ci 224462306a36Sopenharmony_ci /* last one in storage */ 224562306a36Sopenharmony_ci dropped = &mib->counters[dev->info->mib_cnt]; 224662306a36Sopenharmony_ci 224762306a36Sopenharmony_ci /* Some ports may not have MIB counters after SWITCH_COUNTER_NUM. */ 224862306a36Sopenharmony_ci while (mib->cnt_ptr < dev->info->mib_cnt) { 224962306a36Sopenharmony_ci dev->dev_ops->r_mib_pkt(dev, port, mib->cnt_ptr, 225062306a36Sopenharmony_ci dropped, &mib->counters[mib->cnt_ptr]); 225162306a36Sopenharmony_ci ++mib->cnt_ptr; 225262306a36Sopenharmony_ci } 225362306a36Sopenharmony_ci mib->cnt_ptr = 0; 225462306a36Sopenharmony_ci} 225562306a36Sopenharmony_ci 225662306a36Sopenharmony_cistatic void ksz_mib_read_work(struct work_struct *work) 225762306a36Sopenharmony_ci{ 225862306a36Sopenharmony_ci struct ksz_device *dev = container_of(work, struct ksz_device, 225962306a36Sopenharmony_ci mib_read.work); 226062306a36Sopenharmony_ci struct ksz_port_mib *mib; 226162306a36Sopenharmony_ci struct ksz_port *p; 226262306a36Sopenharmony_ci int i; 226362306a36Sopenharmony_ci 226462306a36Sopenharmony_ci for (i = 0; i < dev->info->port_cnt; i++) { 226562306a36Sopenharmony_ci if (dsa_is_unused_port(dev->ds, i)) 226662306a36Sopenharmony_ci continue; 226762306a36Sopenharmony_ci 226862306a36Sopenharmony_ci p = &dev->ports[i]; 226962306a36Sopenharmony_ci mib = &p->mib; 227062306a36Sopenharmony_ci mutex_lock(&mib->cnt_mutex); 227162306a36Sopenharmony_ci 227262306a36Sopenharmony_ci /* Only read MIB counters when the port is told to do. 227362306a36Sopenharmony_ci * If not, read only dropped counters when link is not up. 227462306a36Sopenharmony_ci */ 227562306a36Sopenharmony_ci if (!p->read) { 227662306a36Sopenharmony_ci const struct dsa_port *dp = dsa_to_port(dev->ds, i); 227762306a36Sopenharmony_ci 227862306a36Sopenharmony_ci if (!netif_carrier_ok(dp->slave)) 227962306a36Sopenharmony_ci mib->cnt_ptr = dev->info->reg_mib_cnt; 228062306a36Sopenharmony_ci } 228162306a36Sopenharmony_ci port_r_cnt(dev, i); 228262306a36Sopenharmony_ci p->read = false; 228362306a36Sopenharmony_ci 228462306a36Sopenharmony_ci if (dev->dev_ops->r_mib_stat64) 228562306a36Sopenharmony_ci dev->dev_ops->r_mib_stat64(dev, i); 228662306a36Sopenharmony_ci 228762306a36Sopenharmony_ci mutex_unlock(&mib->cnt_mutex); 228862306a36Sopenharmony_ci } 228962306a36Sopenharmony_ci 229062306a36Sopenharmony_ci schedule_delayed_work(&dev->mib_read, dev->mib_read_interval); 229162306a36Sopenharmony_ci} 229262306a36Sopenharmony_ci 229362306a36Sopenharmony_civoid ksz_init_mib_timer(struct ksz_device *dev) 229462306a36Sopenharmony_ci{ 229562306a36Sopenharmony_ci int i; 229662306a36Sopenharmony_ci 229762306a36Sopenharmony_ci INIT_DELAYED_WORK(&dev->mib_read, ksz_mib_read_work); 229862306a36Sopenharmony_ci 229962306a36Sopenharmony_ci for (i = 0; i < dev->info->port_cnt; i++) { 230062306a36Sopenharmony_ci struct ksz_port_mib *mib = &dev->ports[i].mib; 230162306a36Sopenharmony_ci 230262306a36Sopenharmony_ci dev->dev_ops->port_init_cnt(dev, i); 230362306a36Sopenharmony_ci 230462306a36Sopenharmony_ci mib->cnt_ptr = 0; 230562306a36Sopenharmony_ci memset(mib->counters, 0, dev->info->mib_cnt * sizeof(u64)); 230662306a36Sopenharmony_ci } 230762306a36Sopenharmony_ci} 230862306a36Sopenharmony_ci 230962306a36Sopenharmony_cistatic int ksz_phy_read16(struct dsa_switch *ds, int addr, int reg) 231062306a36Sopenharmony_ci{ 231162306a36Sopenharmony_ci struct ksz_device *dev = ds->priv; 231262306a36Sopenharmony_ci u16 val = 0xffff; 231362306a36Sopenharmony_ci int ret; 231462306a36Sopenharmony_ci 231562306a36Sopenharmony_ci ret = dev->dev_ops->r_phy(dev, addr, reg, &val); 231662306a36Sopenharmony_ci if (ret) 231762306a36Sopenharmony_ci return ret; 231862306a36Sopenharmony_ci 231962306a36Sopenharmony_ci return val; 232062306a36Sopenharmony_ci} 232162306a36Sopenharmony_ci 232262306a36Sopenharmony_cistatic int ksz_phy_write16(struct dsa_switch *ds, int addr, int reg, u16 val) 232362306a36Sopenharmony_ci{ 232462306a36Sopenharmony_ci struct ksz_device *dev = ds->priv; 232562306a36Sopenharmony_ci int ret; 232662306a36Sopenharmony_ci 232762306a36Sopenharmony_ci ret = dev->dev_ops->w_phy(dev, addr, reg, val); 232862306a36Sopenharmony_ci if (ret) 232962306a36Sopenharmony_ci return ret; 233062306a36Sopenharmony_ci 233162306a36Sopenharmony_ci return 0; 233262306a36Sopenharmony_ci} 233362306a36Sopenharmony_ci 233462306a36Sopenharmony_cistatic u32 ksz_get_phy_flags(struct dsa_switch *ds, int port) 233562306a36Sopenharmony_ci{ 233662306a36Sopenharmony_ci struct ksz_device *dev = ds->priv; 233762306a36Sopenharmony_ci 233862306a36Sopenharmony_ci switch (dev->chip_id) { 233962306a36Sopenharmony_ci case KSZ8830_CHIP_ID: 234062306a36Sopenharmony_ci /* Silicon Errata Sheet (DS80000830A): 234162306a36Sopenharmony_ci * Port 1 does not work with LinkMD Cable-Testing. 234262306a36Sopenharmony_ci * Port 1 does not respond to received PAUSE control frames. 234362306a36Sopenharmony_ci */ 234462306a36Sopenharmony_ci if (!port) 234562306a36Sopenharmony_ci return MICREL_KSZ8_P1_ERRATA; 234662306a36Sopenharmony_ci break; 234762306a36Sopenharmony_ci case KSZ9477_CHIP_ID: 234862306a36Sopenharmony_ci /* KSZ9477 Errata DS80000754C 234962306a36Sopenharmony_ci * 235062306a36Sopenharmony_ci * Module 4: Energy Efficient Ethernet (EEE) feature select must 235162306a36Sopenharmony_ci * be manually disabled 235262306a36Sopenharmony_ci * The EEE feature is enabled by default, but it is not fully 235362306a36Sopenharmony_ci * operational. It must be manually disabled through register 235462306a36Sopenharmony_ci * controls. If not disabled, the PHY ports can auto-negotiate 235562306a36Sopenharmony_ci * to enable EEE, and this feature can cause link drops when 235662306a36Sopenharmony_ci * linked to another device supporting EEE. 235762306a36Sopenharmony_ci */ 235862306a36Sopenharmony_ci return MICREL_NO_EEE; 235962306a36Sopenharmony_ci } 236062306a36Sopenharmony_ci 236162306a36Sopenharmony_ci return 0; 236262306a36Sopenharmony_ci} 236362306a36Sopenharmony_ci 236462306a36Sopenharmony_cistatic void ksz_mac_link_down(struct dsa_switch *ds, int port, 236562306a36Sopenharmony_ci unsigned int mode, phy_interface_t interface) 236662306a36Sopenharmony_ci{ 236762306a36Sopenharmony_ci struct ksz_device *dev = ds->priv; 236862306a36Sopenharmony_ci struct ksz_port *p = &dev->ports[port]; 236962306a36Sopenharmony_ci 237062306a36Sopenharmony_ci /* Read all MIB counters when the link is going down. */ 237162306a36Sopenharmony_ci p->read = true; 237262306a36Sopenharmony_ci /* timer started */ 237362306a36Sopenharmony_ci if (dev->mib_read_interval) 237462306a36Sopenharmony_ci schedule_delayed_work(&dev->mib_read, 0); 237562306a36Sopenharmony_ci} 237662306a36Sopenharmony_ci 237762306a36Sopenharmony_cistatic int ksz_sset_count(struct dsa_switch *ds, int port, int sset) 237862306a36Sopenharmony_ci{ 237962306a36Sopenharmony_ci struct ksz_device *dev = ds->priv; 238062306a36Sopenharmony_ci 238162306a36Sopenharmony_ci if (sset != ETH_SS_STATS) 238262306a36Sopenharmony_ci return 0; 238362306a36Sopenharmony_ci 238462306a36Sopenharmony_ci return dev->info->mib_cnt; 238562306a36Sopenharmony_ci} 238662306a36Sopenharmony_ci 238762306a36Sopenharmony_cistatic void ksz_get_ethtool_stats(struct dsa_switch *ds, int port, 238862306a36Sopenharmony_ci uint64_t *buf) 238962306a36Sopenharmony_ci{ 239062306a36Sopenharmony_ci const struct dsa_port *dp = dsa_to_port(ds, port); 239162306a36Sopenharmony_ci struct ksz_device *dev = ds->priv; 239262306a36Sopenharmony_ci struct ksz_port_mib *mib; 239362306a36Sopenharmony_ci 239462306a36Sopenharmony_ci mib = &dev->ports[port].mib; 239562306a36Sopenharmony_ci mutex_lock(&mib->cnt_mutex); 239662306a36Sopenharmony_ci 239762306a36Sopenharmony_ci /* Only read dropped counters if no link. */ 239862306a36Sopenharmony_ci if (!netif_carrier_ok(dp->slave)) 239962306a36Sopenharmony_ci mib->cnt_ptr = dev->info->reg_mib_cnt; 240062306a36Sopenharmony_ci port_r_cnt(dev, port); 240162306a36Sopenharmony_ci memcpy(buf, mib->counters, dev->info->mib_cnt * sizeof(u64)); 240262306a36Sopenharmony_ci mutex_unlock(&mib->cnt_mutex); 240362306a36Sopenharmony_ci} 240462306a36Sopenharmony_ci 240562306a36Sopenharmony_cistatic int ksz_port_bridge_join(struct dsa_switch *ds, int port, 240662306a36Sopenharmony_ci struct dsa_bridge bridge, 240762306a36Sopenharmony_ci bool *tx_fwd_offload, 240862306a36Sopenharmony_ci struct netlink_ext_ack *extack) 240962306a36Sopenharmony_ci{ 241062306a36Sopenharmony_ci /* port_stp_state_set() will be called after to put the port in 241162306a36Sopenharmony_ci * appropriate state so there is no need to do anything. 241262306a36Sopenharmony_ci */ 241362306a36Sopenharmony_ci 241462306a36Sopenharmony_ci return 0; 241562306a36Sopenharmony_ci} 241662306a36Sopenharmony_ci 241762306a36Sopenharmony_cistatic void ksz_port_bridge_leave(struct dsa_switch *ds, int port, 241862306a36Sopenharmony_ci struct dsa_bridge bridge) 241962306a36Sopenharmony_ci{ 242062306a36Sopenharmony_ci /* port_stp_state_set() will be called after to put the port in 242162306a36Sopenharmony_ci * forwarding state so there is no need to do anything. 242262306a36Sopenharmony_ci */ 242362306a36Sopenharmony_ci} 242462306a36Sopenharmony_ci 242562306a36Sopenharmony_cistatic void ksz_port_fast_age(struct dsa_switch *ds, int port) 242662306a36Sopenharmony_ci{ 242762306a36Sopenharmony_ci struct ksz_device *dev = ds->priv; 242862306a36Sopenharmony_ci 242962306a36Sopenharmony_ci dev->dev_ops->flush_dyn_mac_table(dev, port); 243062306a36Sopenharmony_ci} 243162306a36Sopenharmony_ci 243262306a36Sopenharmony_cistatic int ksz_set_ageing_time(struct dsa_switch *ds, unsigned int msecs) 243362306a36Sopenharmony_ci{ 243462306a36Sopenharmony_ci struct ksz_device *dev = ds->priv; 243562306a36Sopenharmony_ci 243662306a36Sopenharmony_ci if (!dev->dev_ops->set_ageing_time) 243762306a36Sopenharmony_ci return -EOPNOTSUPP; 243862306a36Sopenharmony_ci 243962306a36Sopenharmony_ci return dev->dev_ops->set_ageing_time(dev, msecs); 244062306a36Sopenharmony_ci} 244162306a36Sopenharmony_ci 244262306a36Sopenharmony_cistatic int ksz_port_fdb_add(struct dsa_switch *ds, int port, 244362306a36Sopenharmony_ci const unsigned char *addr, u16 vid, 244462306a36Sopenharmony_ci struct dsa_db db) 244562306a36Sopenharmony_ci{ 244662306a36Sopenharmony_ci struct ksz_device *dev = ds->priv; 244762306a36Sopenharmony_ci 244862306a36Sopenharmony_ci if (!dev->dev_ops->fdb_add) 244962306a36Sopenharmony_ci return -EOPNOTSUPP; 245062306a36Sopenharmony_ci 245162306a36Sopenharmony_ci return dev->dev_ops->fdb_add(dev, port, addr, vid, db); 245262306a36Sopenharmony_ci} 245362306a36Sopenharmony_ci 245462306a36Sopenharmony_cistatic int ksz_port_fdb_del(struct dsa_switch *ds, int port, 245562306a36Sopenharmony_ci const unsigned char *addr, 245662306a36Sopenharmony_ci u16 vid, struct dsa_db db) 245762306a36Sopenharmony_ci{ 245862306a36Sopenharmony_ci struct ksz_device *dev = ds->priv; 245962306a36Sopenharmony_ci 246062306a36Sopenharmony_ci if (!dev->dev_ops->fdb_del) 246162306a36Sopenharmony_ci return -EOPNOTSUPP; 246262306a36Sopenharmony_ci 246362306a36Sopenharmony_ci return dev->dev_ops->fdb_del(dev, port, addr, vid, db); 246462306a36Sopenharmony_ci} 246562306a36Sopenharmony_ci 246662306a36Sopenharmony_cistatic int ksz_port_fdb_dump(struct dsa_switch *ds, int port, 246762306a36Sopenharmony_ci dsa_fdb_dump_cb_t *cb, void *data) 246862306a36Sopenharmony_ci{ 246962306a36Sopenharmony_ci struct ksz_device *dev = ds->priv; 247062306a36Sopenharmony_ci 247162306a36Sopenharmony_ci if (!dev->dev_ops->fdb_dump) 247262306a36Sopenharmony_ci return -EOPNOTSUPP; 247362306a36Sopenharmony_ci 247462306a36Sopenharmony_ci return dev->dev_ops->fdb_dump(dev, port, cb, data); 247562306a36Sopenharmony_ci} 247662306a36Sopenharmony_ci 247762306a36Sopenharmony_cistatic int ksz_port_mdb_add(struct dsa_switch *ds, int port, 247862306a36Sopenharmony_ci const struct switchdev_obj_port_mdb *mdb, 247962306a36Sopenharmony_ci struct dsa_db db) 248062306a36Sopenharmony_ci{ 248162306a36Sopenharmony_ci struct ksz_device *dev = ds->priv; 248262306a36Sopenharmony_ci 248362306a36Sopenharmony_ci if (!dev->dev_ops->mdb_add) 248462306a36Sopenharmony_ci return -EOPNOTSUPP; 248562306a36Sopenharmony_ci 248662306a36Sopenharmony_ci return dev->dev_ops->mdb_add(dev, port, mdb, db); 248762306a36Sopenharmony_ci} 248862306a36Sopenharmony_ci 248962306a36Sopenharmony_cistatic int ksz_port_mdb_del(struct dsa_switch *ds, int port, 249062306a36Sopenharmony_ci const struct switchdev_obj_port_mdb *mdb, 249162306a36Sopenharmony_ci struct dsa_db db) 249262306a36Sopenharmony_ci{ 249362306a36Sopenharmony_ci struct ksz_device *dev = ds->priv; 249462306a36Sopenharmony_ci 249562306a36Sopenharmony_ci if (!dev->dev_ops->mdb_del) 249662306a36Sopenharmony_ci return -EOPNOTSUPP; 249762306a36Sopenharmony_ci 249862306a36Sopenharmony_ci return dev->dev_ops->mdb_del(dev, port, mdb, db); 249962306a36Sopenharmony_ci} 250062306a36Sopenharmony_ci 250162306a36Sopenharmony_cistatic int ksz_enable_port(struct dsa_switch *ds, int port, 250262306a36Sopenharmony_ci struct phy_device *phy) 250362306a36Sopenharmony_ci{ 250462306a36Sopenharmony_ci struct ksz_device *dev = ds->priv; 250562306a36Sopenharmony_ci 250662306a36Sopenharmony_ci if (!dsa_is_user_port(ds, port)) 250762306a36Sopenharmony_ci return 0; 250862306a36Sopenharmony_ci 250962306a36Sopenharmony_ci /* setup slave port */ 251062306a36Sopenharmony_ci dev->dev_ops->port_setup(dev, port, false); 251162306a36Sopenharmony_ci 251262306a36Sopenharmony_ci /* port_stp_state_set() will be called after to enable the port so 251362306a36Sopenharmony_ci * there is no need to do anything. 251462306a36Sopenharmony_ci */ 251562306a36Sopenharmony_ci 251662306a36Sopenharmony_ci return 0; 251762306a36Sopenharmony_ci} 251862306a36Sopenharmony_ci 251962306a36Sopenharmony_civoid ksz_port_stp_state_set(struct dsa_switch *ds, int port, u8 state) 252062306a36Sopenharmony_ci{ 252162306a36Sopenharmony_ci struct ksz_device *dev = ds->priv; 252262306a36Sopenharmony_ci struct ksz_port *p; 252362306a36Sopenharmony_ci const u16 *regs; 252462306a36Sopenharmony_ci u8 data; 252562306a36Sopenharmony_ci 252662306a36Sopenharmony_ci regs = dev->info->regs; 252762306a36Sopenharmony_ci 252862306a36Sopenharmony_ci ksz_pread8(dev, port, regs[P_STP_CTRL], &data); 252962306a36Sopenharmony_ci data &= ~(PORT_TX_ENABLE | PORT_RX_ENABLE | PORT_LEARN_DISABLE); 253062306a36Sopenharmony_ci 253162306a36Sopenharmony_ci p = &dev->ports[port]; 253262306a36Sopenharmony_ci 253362306a36Sopenharmony_ci switch (state) { 253462306a36Sopenharmony_ci case BR_STATE_DISABLED: 253562306a36Sopenharmony_ci data |= PORT_LEARN_DISABLE; 253662306a36Sopenharmony_ci break; 253762306a36Sopenharmony_ci case BR_STATE_LISTENING: 253862306a36Sopenharmony_ci data |= (PORT_RX_ENABLE | PORT_LEARN_DISABLE); 253962306a36Sopenharmony_ci break; 254062306a36Sopenharmony_ci case BR_STATE_LEARNING: 254162306a36Sopenharmony_ci data |= PORT_RX_ENABLE; 254262306a36Sopenharmony_ci if (!p->learning) 254362306a36Sopenharmony_ci data |= PORT_LEARN_DISABLE; 254462306a36Sopenharmony_ci break; 254562306a36Sopenharmony_ci case BR_STATE_FORWARDING: 254662306a36Sopenharmony_ci data |= (PORT_TX_ENABLE | PORT_RX_ENABLE); 254762306a36Sopenharmony_ci if (!p->learning) 254862306a36Sopenharmony_ci data |= PORT_LEARN_DISABLE; 254962306a36Sopenharmony_ci break; 255062306a36Sopenharmony_ci case BR_STATE_BLOCKING: 255162306a36Sopenharmony_ci data |= PORT_LEARN_DISABLE; 255262306a36Sopenharmony_ci break; 255362306a36Sopenharmony_ci default: 255462306a36Sopenharmony_ci dev_err(ds->dev, "invalid STP state: %d\n", state); 255562306a36Sopenharmony_ci return; 255662306a36Sopenharmony_ci } 255762306a36Sopenharmony_ci 255862306a36Sopenharmony_ci ksz_pwrite8(dev, port, regs[P_STP_CTRL], data); 255962306a36Sopenharmony_ci 256062306a36Sopenharmony_ci p->stp_state = state; 256162306a36Sopenharmony_ci 256262306a36Sopenharmony_ci ksz_update_port_member(dev, port); 256362306a36Sopenharmony_ci} 256462306a36Sopenharmony_ci 256562306a36Sopenharmony_cistatic int ksz_port_pre_bridge_flags(struct dsa_switch *ds, int port, 256662306a36Sopenharmony_ci struct switchdev_brport_flags flags, 256762306a36Sopenharmony_ci struct netlink_ext_ack *extack) 256862306a36Sopenharmony_ci{ 256962306a36Sopenharmony_ci if (flags.mask & ~BR_LEARNING) 257062306a36Sopenharmony_ci return -EINVAL; 257162306a36Sopenharmony_ci 257262306a36Sopenharmony_ci return 0; 257362306a36Sopenharmony_ci} 257462306a36Sopenharmony_ci 257562306a36Sopenharmony_cistatic int ksz_port_bridge_flags(struct dsa_switch *ds, int port, 257662306a36Sopenharmony_ci struct switchdev_brport_flags flags, 257762306a36Sopenharmony_ci struct netlink_ext_ack *extack) 257862306a36Sopenharmony_ci{ 257962306a36Sopenharmony_ci struct ksz_device *dev = ds->priv; 258062306a36Sopenharmony_ci struct ksz_port *p = &dev->ports[port]; 258162306a36Sopenharmony_ci 258262306a36Sopenharmony_ci if (flags.mask & BR_LEARNING) { 258362306a36Sopenharmony_ci p->learning = !!(flags.val & BR_LEARNING); 258462306a36Sopenharmony_ci 258562306a36Sopenharmony_ci /* Make the change take effect immediately */ 258662306a36Sopenharmony_ci ksz_port_stp_state_set(ds, port, p->stp_state); 258762306a36Sopenharmony_ci } 258862306a36Sopenharmony_ci 258962306a36Sopenharmony_ci return 0; 259062306a36Sopenharmony_ci} 259162306a36Sopenharmony_ci 259262306a36Sopenharmony_cistatic enum dsa_tag_protocol ksz_get_tag_protocol(struct dsa_switch *ds, 259362306a36Sopenharmony_ci int port, 259462306a36Sopenharmony_ci enum dsa_tag_protocol mp) 259562306a36Sopenharmony_ci{ 259662306a36Sopenharmony_ci struct ksz_device *dev = ds->priv; 259762306a36Sopenharmony_ci enum dsa_tag_protocol proto = DSA_TAG_PROTO_NONE; 259862306a36Sopenharmony_ci 259962306a36Sopenharmony_ci if (dev->chip_id == KSZ8795_CHIP_ID || 260062306a36Sopenharmony_ci dev->chip_id == KSZ8794_CHIP_ID || 260162306a36Sopenharmony_ci dev->chip_id == KSZ8765_CHIP_ID) 260262306a36Sopenharmony_ci proto = DSA_TAG_PROTO_KSZ8795; 260362306a36Sopenharmony_ci 260462306a36Sopenharmony_ci if (dev->chip_id == KSZ8830_CHIP_ID || 260562306a36Sopenharmony_ci dev->chip_id == KSZ8563_CHIP_ID || 260662306a36Sopenharmony_ci dev->chip_id == KSZ9893_CHIP_ID || 260762306a36Sopenharmony_ci dev->chip_id == KSZ9563_CHIP_ID) 260862306a36Sopenharmony_ci proto = DSA_TAG_PROTO_KSZ9893; 260962306a36Sopenharmony_ci 261062306a36Sopenharmony_ci if (dev->chip_id == KSZ9477_CHIP_ID || 261162306a36Sopenharmony_ci dev->chip_id == KSZ9896_CHIP_ID || 261262306a36Sopenharmony_ci dev->chip_id == KSZ9897_CHIP_ID || 261362306a36Sopenharmony_ci dev->chip_id == KSZ9567_CHIP_ID) 261462306a36Sopenharmony_ci proto = DSA_TAG_PROTO_KSZ9477; 261562306a36Sopenharmony_ci 261662306a36Sopenharmony_ci if (is_lan937x(dev)) 261762306a36Sopenharmony_ci proto = DSA_TAG_PROTO_LAN937X_VALUE; 261862306a36Sopenharmony_ci 261962306a36Sopenharmony_ci return proto; 262062306a36Sopenharmony_ci} 262162306a36Sopenharmony_ci 262262306a36Sopenharmony_cistatic int ksz_connect_tag_protocol(struct dsa_switch *ds, 262362306a36Sopenharmony_ci enum dsa_tag_protocol proto) 262462306a36Sopenharmony_ci{ 262562306a36Sopenharmony_ci struct ksz_tagger_data *tagger_data; 262662306a36Sopenharmony_ci 262762306a36Sopenharmony_ci switch (proto) { 262862306a36Sopenharmony_ci case DSA_TAG_PROTO_KSZ8795: 262962306a36Sopenharmony_ci return 0; 263062306a36Sopenharmony_ci case DSA_TAG_PROTO_KSZ9893: 263162306a36Sopenharmony_ci case DSA_TAG_PROTO_KSZ9477: 263262306a36Sopenharmony_ci case DSA_TAG_PROTO_LAN937X: 263362306a36Sopenharmony_ci tagger_data = ksz_tagger_data(ds); 263462306a36Sopenharmony_ci tagger_data->xmit_work_fn = ksz_port_deferred_xmit; 263562306a36Sopenharmony_ci return 0; 263662306a36Sopenharmony_ci default: 263762306a36Sopenharmony_ci return -EPROTONOSUPPORT; 263862306a36Sopenharmony_ci } 263962306a36Sopenharmony_ci} 264062306a36Sopenharmony_ci 264162306a36Sopenharmony_cistatic int ksz_port_vlan_filtering(struct dsa_switch *ds, int port, 264262306a36Sopenharmony_ci bool flag, struct netlink_ext_ack *extack) 264362306a36Sopenharmony_ci{ 264462306a36Sopenharmony_ci struct ksz_device *dev = ds->priv; 264562306a36Sopenharmony_ci 264662306a36Sopenharmony_ci if (!dev->dev_ops->vlan_filtering) 264762306a36Sopenharmony_ci return -EOPNOTSUPP; 264862306a36Sopenharmony_ci 264962306a36Sopenharmony_ci return dev->dev_ops->vlan_filtering(dev, port, flag, extack); 265062306a36Sopenharmony_ci} 265162306a36Sopenharmony_ci 265262306a36Sopenharmony_cistatic int ksz_port_vlan_add(struct dsa_switch *ds, int port, 265362306a36Sopenharmony_ci const struct switchdev_obj_port_vlan *vlan, 265462306a36Sopenharmony_ci struct netlink_ext_ack *extack) 265562306a36Sopenharmony_ci{ 265662306a36Sopenharmony_ci struct ksz_device *dev = ds->priv; 265762306a36Sopenharmony_ci 265862306a36Sopenharmony_ci if (!dev->dev_ops->vlan_add) 265962306a36Sopenharmony_ci return -EOPNOTSUPP; 266062306a36Sopenharmony_ci 266162306a36Sopenharmony_ci return dev->dev_ops->vlan_add(dev, port, vlan, extack); 266262306a36Sopenharmony_ci} 266362306a36Sopenharmony_ci 266462306a36Sopenharmony_cistatic int ksz_port_vlan_del(struct dsa_switch *ds, int port, 266562306a36Sopenharmony_ci const struct switchdev_obj_port_vlan *vlan) 266662306a36Sopenharmony_ci{ 266762306a36Sopenharmony_ci struct ksz_device *dev = ds->priv; 266862306a36Sopenharmony_ci 266962306a36Sopenharmony_ci if (!dev->dev_ops->vlan_del) 267062306a36Sopenharmony_ci return -EOPNOTSUPP; 267162306a36Sopenharmony_ci 267262306a36Sopenharmony_ci return dev->dev_ops->vlan_del(dev, port, vlan); 267362306a36Sopenharmony_ci} 267462306a36Sopenharmony_ci 267562306a36Sopenharmony_cistatic int ksz_port_mirror_add(struct dsa_switch *ds, int port, 267662306a36Sopenharmony_ci struct dsa_mall_mirror_tc_entry *mirror, 267762306a36Sopenharmony_ci bool ingress, struct netlink_ext_ack *extack) 267862306a36Sopenharmony_ci{ 267962306a36Sopenharmony_ci struct ksz_device *dev = ds->priv; 268062306a36Sopenharmony_ci 268162306a36Sopenharmony_ci if (!dev->dev_ops->mirror_add) 268262306a36Sopenharmony_ci return -EOPNOTSUPP; 268362306a36Sopenharmony_ci 268462306a36Sopenharmony_ci return dev->dev_ops->mirror_add(dev, port, mirror, ingress, extack); 268562306a36Sopenharmony_ci} 268662306a36Sopenharmony_ci 268762306a36Sopenharmony_cistatic void ksz_port_mirror_del(struct dsa_switch *ds, int port, 268862306a36Sopenharmony_ci struct dsa_mall_mirror_tc_entry *mirror) 268962306a36Sopenharmony_ci{ 269062306a36Sopenharmony_ci struct ksz_device *dev = ds->priv; 269162306a36Sopenharmony_ci 269262306a36Sopenharmony_ci if (dev->dev_ops->mirror_del) 269362306a36Sopenharmony_ci dev->dev_ops->mirror_del(dev, port, mirror); 269462306a36Sopenharmony_ci} 269562306a36Sopenharmony_ci 269662306a36Sopenharmony_cistatic int ksz_change_mtu(struct dsa_switch *ds, int port, int mtu) 269762306a36Sopenharmony_ci{ 269862306a36Sopenharmony_ci struct ksz_device *dev = ds->priv; 269962306a36Sopenharmony_ci 270062306a36Sopenharmony_ci if (!dev->dev_ops->change_mtu) 270162306a36Sopenharmony_ci return -EOPNOTSUPP; 270262306a36Sopenharmony_ci 270362306a36Sopenharmony_ci return dev->dev_ops->change_mtu(dev, port, mtu); 270462306a36Sopenharmony_ci} 270562306a36Sopenharmony_ci 270662306a36Sopenharmony_cistatic int ksz_max_mtu(struct dsa_switch *ds, int port) 270762306a36Sopenharmony_ci{ 270862306a36Sopenharmony_ci struct ksz_device *dev = ds->priv; 270962306a36Sopenharmony_ci 271062306a36Sopenharmony_ci switch (dev->chip_id) { 271162306a36Sopenharmony_ci case KSZ8795_CHIP_ID: 271262306a36Sopenharmony_ci case KSZ8794_CHIP_ID: 271362306a36Sopenharmony_ci case KSZ8765_CHIP_ID: 271462306a36Sopenharmony_ci return KSZ8795_HUGE_PACKET_SIZE - VLAN_ETH_HLEN - ETH_FCS_LEN; 271562306a36Sopenharmony_ci case KSZ8830_CHIP_ID: 271662306a36Sopenharmony_ci return KSZ8863_HUGE_PACKET_SIZE - VLAN_ETH_HLEN - ETH_FCS_LEN; 271762306a36Sopenharmony_ci case KSZ8563_CHIP_ID: 271862306a36Sopenharmony_ci case KSZ9477_CHIP_ID: 271962306a36Sopenharmony_ci case KSZ9563_CHIP_ID: 272062306a36Sopenharmony_ci case KSZ9567_CHIP_ID: 272162306a36Sopenharmony_ci case KSZ9893_CHIP_ID: 272262306a36Sopenharmony_ci case KSZ9896_CHIP_ID: 272362306a36Sopenharmony_ci case KSZ9897_CHIP_ID: 272462306a36Sopenharmony_ci case LAN9370_CHIP_ID: 272562306a36Sopenharmony_ci case LAN9371_CHIP_ID: 272662306a36Sopenharmony_ci case LAN9372_CHIP_ID: 272762306a36Sopenharmony_ci case LAN9373_CHIP_ID: 272862306a36Sopenharmony_ci case LAN9374_CHIP_ID: 272962306a36Sopenharmony_ci return KSZ9477_MAX_FRAME_SIZE - VLAN_ETH_HLEN - ETH_FCS_LEN; 273062306a36Sopenharmony_ci } 273162306a36Sopenharmony_ci 273262306a36Sopenharmony_ci return -EOPNOTSUPP; 273362306a36Sopenharmony_ci} 273462306a36Sopenharmony_ci 273562306a36Sopenharmony_cistatic int ksz_validate_eee(struct dsa_switch *ds, int port) 273662306a36Sopenharmony_ci{ 273762306a36Sopenharmony_ci struct ksz_device *dev = ds->priv; 273862306a36Sopenharmony_ci 273962306a36Sopenharmony_ci if (!dev->info->internal_phy[port]) 274062306a36Sopenharmony_ci return -EOPNOTSUPP; 274162306a36Sopenharmony_ci 274262306a36Sopenharmony_ci switch (dev->chip_id) { 274362306a36Sopenharmony_ci case KSZ8563_CHIP_ID: 274462306a36Sopenharmony_ci case KSZ9477_CHIP_ID: 274562306a36Sopenharmony_ci case KSZ9563_CHIP_ID: 274662306a36Sopenharmony_ci case KSZ9567_CHIP_ID: 274762306a36Sopenharmony_ci case KSZ9893_CHIP_ID: 274862306a36Sopenharmony_ci case KSZ9896_CHIP_ID: 274962306a36Sopenharmony_ci case KSZ9897_CHIP_ID: 275062306a36Sopenharmony_ci return 0; 275162306a36Sopenharmony_ci } 275262306a36Sopenharmony_ci 275362306a36Sopenharmony_ci return -EOPNOTSUPP; 275462306a36Sopenharmony_ci} 275562306a36Sopenharmony_ci 275662306a36Sopenharmony_cistatic int ksz_get_mac_eee(struct dsa_switch *ds, int port, 275762306a36Sopenharmony_ci struct ethtool_eee *e) 275862306a36Sopenharmony_ci{ 275962306a36Sopenharmony_ci int ret; 276062306a36Sopenharmony_ci 276162306a36Sopenharmony_ci ret = ksz_validate_eee(ds, port); 276262306a36Sopenharmony_ci if (ret) 276362306a36Sopenharmony_ci return ret; 276462306a36Sopenharmony_ci 276562306a36Sopenharmony_ci /* There is no documented control of Tx LPI configuration. */ 276662306a36Sopenharmony_ci e->tx_lpi_enabled = true; 276762306a36Sopenharmony_ci 276862306a36Sopenharmony_ci /* There is no documented control of Tx LPI timer. According to tests 276962306a36Sopenharmony_ci * Tx LPI timer seems to be set by default to minimal value. 277062306a36Sopenharmony_ci */ 277162306a36Sopenharmony_ci e->tx_lpi_timer = 0; 277262306a36Sopenharmony_ci 277362306a36Sopenharmony_ci return 0; 277462306a36Sopenharmony_ci} 277562306a36Sopenharmony_ci 277662306a36Sopenharmony_cistatic int ksz_set_mac_eee(struct dsa_switch *ds, int port, 277762306a36Sopenharmony_ci struct ethtool_eee *e) 277862306a36Sopenharmony_ci{ 277962306a36Sopenharmony_ci struct ksz_device *dev = ds->priv; 278062306a36Sopenharmony_ci int ret; 278162306a36Sopenharmony_ci 278262306a36Sopenharmony_ci ret = ksz_validate_eee(ds, port); 278362306a36Sopenharmony_ci if (ret) 278462306a36Sopenharmony_ci return ret; 278562306a36Sopenharmony_ci 278662306a36Sopenharmony_ci if (!e->tx_lpi_enabled) { 278762306a36Sopenharmony_ci dev_err(dev->dev, "Disabling EEE Tx LPI is not supported\n"); 278862306a36Sopenharmony_ci return -EINVAL; 278962306a36Sopenharmony_ci } 279062306a36Sopenharmony_ci 279162306a36Sopenharmony_ci if (e->tx_lpi_timer) { 279262306a36Sopenharmony_ci dev_err(dev->dev, "Setting EEE Tx LPI timer is not supported\n"); 279362306a36Sopenharmony_ci return -EINVAL; 279462306a36Sopenharmony_ci } 279562306a36Sopenharmony_ci 279662306a36Sopenharmony_ci return 0; 279762306a36Sopenharmony_ci} 279862306a36Sopenharmony_ci 279962306a36Sopenharmony_cistatic void ksz_set_xmii(struct ksz_device *dev, int port, 280062306a36Sopenharmony_ci phy_interface_t interface) 280162306a36Sopenharmony_ci{ 280262306a36Sopenharmony_ci const u8 *bitval = dev->info->xmii_ctrl1; 280362306a36Sopenharmony_ci struct ksz_port *p = &dev->ports[port]; 280462306a36Sopenharmony_ci const u16 *regs = dev->info->regs; 280562306a36Sopenharmony_ci u8 data8; 280662306a36Sopenharmony_ci 280762306a36Sopenharmony_ci ksz_pread8(dev, port, regs[P_XMII_CTRL_1], &data8); 280862306a36Sopenharmony_ci 280962306a36Sopenharmony_ci data8 &= ~(P_MII_SEL_M | P_RGMII_ID_IG_ENABLE | 281062306a36Sopenharmony_ci P_RGMII_ID_EG_ENABLE); 281162306a36Sopenharmony_ci 281262306a36Sopenharmony_ci switch (interface) { 281362306a36Sopenharmony_ci case PHY_INTERFACE_MODE_MII: 281462306a36Sopenharmony_ci data8 |= bitval[P_MII_SEL]; 281562306a36Sopenharmony_ci break; 281662306a36Sopenharmony_ci case PHY_INTERFACE_MODE_RMII: 281762306a36Sopenharmony_ci data8 |= bitval[P_RMII_SEL]; 281862306a36Sopenharmony_ci break; 281962306a36Sopenharmony_ci case PHY_INTERFACE_MODE_GMII: 282062306a36Sopenharmony_ci data8 |= bitval[P_GMII_SEL]; 282162306a36Sopenharmony_ci break; 282262306a36Sopenharmony_ci case PHY_INTERFACE_MODE_RGMII: 282362306a36Sopenharmony_ci case PHY_INTERFACE_MODE_RGMII_ID: 282462306a36Sopenharmony_ci case PHY_INTERFACE_MODE_RGMII_TXID: 282562306a36Sopenharmony_ci case PHY_INTERFACE_MODE_RGMII_RXID: 282662306a36Sopenharmony_ci data8 |= bitval[P_RGMII_SEL]; 282762306a36Sopenharmony_ci /* On KSZ9893, disable RGMII in-band status support */ 282862306a36Sopenharmony_ci if (dev->chip_id == KSZ9893_CHIP_ID || 282962306a36Sopenharmony_ci dev->chip_id == KSZ8563_CHIP_ID || 283062306a36Sopenharmony_ci dev->chip_id == KSZ9563_CHIP_ID) 283162306a36Sopenharmony_ci data8 &= ~P_MII_MAC_MODE; 283262306a36Sopenharmony_ci break; 283362306a36Sopenharmony_ci default: 283462306a36Sopenharmony_ci dev_err(dev->dev, "Unsupported interface '%s' for port %d\n", 283562306a36Sopenharmony_ci phy_modes(interface), port); 283662306a36Sopenharmony_ci return; 283762306a36Sopenharmony_ci } 283862306a36Sopenharmony_ci 283962306a36Sopenharmony_ci if (p->rgmii_tx_val) 284062306a36Sopenharmony_ci data8 |= P_RGMII_ID_EG_ENABLE; 284162306a36Sopenharmony_ci 284262306a36Sopenharmony_ci if (p->rgmii_rx_val) 284362306a36Sopenharmony_ci data8 |= P_RGMII_ID_IG_ENABLE; 284462306a36Sopenharmony_ci 284562306a36Sopenharmony_ci /* Write the updated value */ 284662306a36Sopenharmony_ci ksz_pwrite8(dev, port, regs[P_XMII_CTRL_1], data8); 284762306a36Sopenharmony_ci} 284862306a36Sopenharmony_ci 284962306a36Sopenharmony_ciphy_interface_t ksz_get_xmii(struct ksz_device *dev, int port, bool gbit) 285062306a36Sopenharmony_ci{ 285162306a36Sopenharmony_ci const u8 *bitval = dev->info->xmii_ctrl1; 285262306a36Sopenharmony_ci const u16 *regs = dev->info->regs; 285362306a36Sopenharmony_ci phy_interface_t interface; 285462306a36Sopenharmony_ci u8 data8; 285562306a36Sopenharmony_ci u8 val; 285662306a36Sopenharmony_ci 285762306a36Sopenharmony_ci ksz_pread8(dev, port, regs[P_XMII_CTRL_1], &data8); 285862306a36Sopenharmony_ci 285962306a36Sopenharmony_ci val = FIELD_GET(P_MII_SEL_M, data8); 286062306a36Sopenharmony_ci 286162306a36Sopenharmony_ci if (val == bitval[P_MII_SEL]) { 286262306a36Sopenharmony_ci if (gbit) 286362306a36Sopenharmony_ci interface = PHY_INTERFACE_MODE_GMII; 286462306a36Sopenharmony_ci else 286562306a36Sopenharmony_ci interface = PHY_INTERFACE_MODE_MII; 286662306a36Sopenharmony_ci } else if (val == bitval[P_RMII_SEL]) { 286762306a36Sopenharmony_ci interface = PHY_INTERFACE_MODE_RGMII; 286862306a36Sopenharmony_ci } else { 286962306a36Sopenharmony_ci interface = PHY_INTERFACE_MODE_RGMII; 287062306a36Sopenharmony_ci if (data8 & P_RGMII_ID_EG_ENABLE) 287162306a36Sopenharmony_ci interface = PHY_INTERFACE_MODE_RGMII_TXID; 287262306a36Sopenharmony_ci if (data8 & P_RGMII_ID_IG_ENABLE) { 287362306a36Sopenharmony_ci interface = PHY_INTERFACE_MODE_RGMII_RXID; 287462306a36Sopenharmony_ci if (data8 & P_RGMII_ID_EG_ENABLE) 287562306a36Sopenharmony_ci interface = PHY_INTERFACE_MODE_RGMII_ID; 287662306a36Sopenharmony_ci } 287762306a36Sopenharmony_ci } 287862306a36Sopenharmony_ci 287962306a36Sopenharmony_ci return interface; 288062306a36Sopenharmony_ci} 288162306a36Sopenharmony_ci 288262306a36Sopenharmony_cistatic void ksz_phylink_mac_config(struct dsa_switch *ds, int port, 288362306a36Sopenharmony_ci unsigned int mode, 288462306a36Sopenharmony_ci const struct phylink_link_state *state) 288562306a36Sopenharmony_ci{ 288662306a36Sopenharmony_ci struct ksz_device *dev = ds->priv; 288762306a36Sopenharmony_ci 288862306a36Sopenharmony_ci if (ksz_is_ksz88x3(dev)) 288962306a36Sopenharmony_ci return; 289062306a36Sopenharmony_ci 289162306a36Sopenharmony_ci /* Internal PHYs */ 289262306a36Sopenharmony_ci if (dev->info->internal_phy[port]) 289362306a36Sopenharmony_ci return; 289462306a36Sopenharmony_ci 289562306a36Sopenharmony_ci if (phylink_autoneg_inband(mode)) { 289662306a36Sopenharmony_ci dev_err(dev->dev, "In-band AN not supported!\n"); 289762306a36Sopenharmony_ci return; 289862306a36Sopenharmony_ci } 289962306a36Sopenharmony_ci 290062306a36Sopenharmony_ci ksz_set_xmii(dev, port, state->interface); 290162306a36Sopenharmony_ci 290262306a36Sopenharmony_ci if (dev->dev_ops->phylink_mac_config) 290362306a36Sopenharmony_ci dev->dev_ops->phylink_mac_config(dev, port, mode, state); 290462306a36Sopenharmony_ci 290562306a36Sopenharmony_ci if (dev->dev_ops->setup_rgmii_delay) 290662306a36Sopenharmony_ci dev->dev_ops->setup_rgmii_delay(dev, port); 290762306a36Sopenharmony_ci} 290862306a36Sopenharmony_ci 290962306a36Sopenharmony_cibool ksz_get_gbit(struct ksz_device *dev, int port) 291062306a36Sopenharmony_ci{ 291162306a36Sopenharmony_ci const u8 *bitval = dev->info->xmii_ctrl1; 291262306a36Sopenharmony_ci const u16 *regs = dev->info->regs; 291362306a36Sopenharmony_ci bool gbit = false; 291462306a36Sopenharmony_ci u8 data8; 291562306a36Sopenharmony_ci bool val; 291662306a36Sopenharmony_ci 291762306a36Sopenharmony_ci ksz_pread8(dev, port, regs[P_XMII_CTRL_1], &data8); 291862306a36Sopenharmony_ci 291962306a36Sopenharmony_ci val = FIELD_GET(P_GMII_1GBIT_M, data8); 292062306a36Sopenharmony_ci 292162306a36Sopenharmony_ci if (val == bitval[P_GMII_1GBIT]) 292262306a36Sopenharmony_ci gbit = true; 292362306a36Sopenharmony_ci 292462306a36Sopenharmony_ci return gbit; 292562306a36Sopenharmony_ci} 292662306a36Sopenharmony_ci 292762306a36Sopenharmony_cistatic void ksz_set_gbit(struct ksz_device *dev, int port, bool gbit) 292862306a36Sopenharmony_ci{ 292962306a36Sopenharmony_ci const u8 *bitval = dev->info->xmii_ctrl1; 293062306a36Sopenharmony_ci const u16 *regs = dev->info->regs; 293162306a36Sopenharmony_ci u8 data8; 293262306a36Sopenharmony_ci 293362306a36Sopenharmony_ci ksz_pread8(dev, port, regs[P_XMII_CTRL_1], &data8); 293462306a36Sopenharmony_ci 293562306a36Sopenharmony_ci data8 &= ~P_GMII_1GBIT_M; 293662306a36Sopenharmony_ci 293762306a36Sopenharmony_ci if (gbit) 293862306a36Sopenharmony_ci data8 |= FIELD_PREP(P_GMII_1GBIT_M, bitval[P_GMII_1GBIT]); 293962306a36Sopenharmony_ci else 294062306a36Sopenharmony_ci data8 |= FIELD_PREP(P_GMII_1GBIT_M, bitval[P_GMII_NOT_1GBIT]); 294162306a36Sopenharmony_ci 294262306a36Sopenharmony_ci /* Write the updated value */ 294362306a36Sopenharmony_ci ksz_pwrite8(dev, port, regs[P_XMII_CTRL_1], data8); 294462306a36Sopenharmony_ci} 294562306a36Sopenharmony_ci 294662306a36Sopenharmony_cistatic void ksz_set_100_10mbit(struct ksz_device *dev, int port, int speed) 294762306a36Sopenharmony_ci{ 294862306a36Sopenharmony_ci const u8 *bitval = dev->info->xmii_ctrl0; 294962306a36Sopenharmony_ci const u16 *regs = dev->info->regs; 295062306a36Sopenharmony_ci u8 data8; 295162306a36Sopenharmony_ci 295262306a36Sopenharmony_ci ksz_pread8(dev, port, regs[P_XMII_CTRL_0], &data8); 295362306a36Sopenharmony_ci 295462306a36Sopenharmony_ci data8 &= ~P_MII_100MBIT_M; 295562306a36Sopenharmony_ci 295662306a36Sopenharmony_ci if (speed == SPEED_100) 295762306a36Sopenharmony_ci data8 |= FIELD_PREP(P_MII_100MBIT_M, bitval[P_MII_100MBIT]); 295862306a36Sopenharmony_ci else 295962306a36Sopenharmony_ci data8 |= FIELD_PREP(P_MII_100MBIT_M, bitval[P_MII_10MBIT]); 296062306a36Sopenharmony_ci 296162306a36Sopenharmony_ci /* Write the updated value */ 296262306a36Sopenharmony_ci ksz_pwrite8(dev, port, regs[P_XMII_CTRL_0], data8); 296362306a36Sopenharmony_ci} 296462306a36Sopenharmony_ci 296562306a36Sopenharmony_cistatic void ksz_port_set_xmii_speed(struct ksz_device *dev, int port, int speed) 296662306a36Sopenharmony_ci{ 296762306a36Sopenharmony_ci if (speed == SPEED_1000) 296862306a36Sopenharmony_ci ksz_set_gbit(dev, port, true); 296962306a36Sopenharmony_ci else 297062306a36Sopenharmony_ci ksz_set_gbit(dev, port, false); 297162306a36Sopenharmony_ci 297262306a36Sopenharmony_ci if (speed == SPEED_100 || speed == SPEED_10) 297362306a36Sopenharmony_ci ksz_set_100_10mbit(dev, port, speed); 297462306a36Sopenharmony_ci} 297562306a36Sopenharmony_ci 297662306a36Sopenharmony_cistatic void ksz_duplex_flowctrl(struct ksz_device *dev, int port, int duplex, 297762306a36Sopenharmony_ci bool tx_pause, bool rx_pause) 297862306a36Sopenharmony_ci{ 297962306a36Sopenharmony_ci const u8 *bitval = dev->info->xmii_ctrl0; 298062306a36Sopenharmony_ci const u32 *masks = dev->info->masks; 298162306a36Sopenharmony_ci const u16 *regs = dev->info->regs; 298262306a36Sopenharmony_ci u8 mask; 298362306a36Sopenharmony_ci u8 val; 298462306a36Sopenharmony_ci 298562306a36Sopenharmony_ci mask = P_MII_DUPLEX_M | masks[P_MII_TX_FLOW_CTRL] | 298662306a36Sopenharmony_ci masks[P_MII_RX_FLOW_CTRL]; 298762306a36Sopenharmony_ci 298862306a36Sopenharmony_ci if (duplex == DUPLEX_FULL) 298962306a36Sopenharmony_ci val = FIELD_PREP(P_MII_DUPLEX_M, bitval[P_MII_FULL_DUPLEX]); 299062306a36Sopenharmony_ci else 299162306a36Sopenharmony_ci val = FIELD_PREP(P_MII_DUPLEX_M, bitval[P_MII_HALF_DUPLEX]); 299262306a36Sopenharmony_ci 299362306a36Sopenharmony_ci if (tx_pause) 299462306a36Sopenharmony_ci val |= masks[P_MII_TX_FLOW_CTRL]; 299562306a36Sopenharmony_ci 299662306a36Sopenharmony_ci if (rx_pause) 299762306a36Sopenharmony_ci val |= masks[P_MII_RX_FLOW_CTRL]; 299862306a36Sopenharmony_ci 299962306a36Sopenharmony_ci ksz_prmw8(dev, port, regs[P_XMII_CTRL_0], mask, val); 300062306a36Sopenharmony_ci} 300162306a36Sopenharmony_ci 300262306a36Sopenharmony_cistatic void ksz9477_phylink_mac_link_up(struct ksz_device *dev, int port, 300362306a36Sopenharmony_ci unsigned int mode, 300462306a36Sopenharmony_ci phy_interface_t interface, 300562306a36Sopenharmony_ci struct phy_device *phydev, int speed, 300662306a36Sopenharmony_ci int duplex, bool tx_pause, 300762306a36Sopenharmony_ci bool rx_pause) 300862306a36Sopenharmony_ci{ 300962306a36Sopenharmony_ci struct ksz_port *p; 301062306a36Sopenharmony_ci 301162306a36Sopenharmony_ci p = &dev->ports[port]; 301262306a36Sopenharmony_ci 301362306a36Sopenharmony_ci /* Internal PHYs */ 301462306a36Sopenharmony_ci if (dev->info->internal_phy[port]) 301562306a36Sopenharmony_ci return; 301662306a36Sopenharmony_ci 301762306a36Sopenharmony_ci p->phydev.speed = speed; 301862306a36Sopenharmony_ci 301962306a36Sopenharmony_ci ksz_port_set_xmii_speed(dev, port, speed); 302062306a36Sopenharmony_ci 302162306a36Sopenharmony_ci ksz_duplex_flowctrl(dev, port, duplex, tx_pause, rx_pause); 302262306a36Sopenharmony_ci} 302362306a36Sopenharmony_ci 302462306a36Sopenharmony_cistatic void ksz_phylink_mac_link_up(struct dsa_switch *ds, int port, 302562306a36Sopenharmony_ci unsigned int mode, 302662306a36Sopenharmony_ci phy_interface_t interface, 302762306a36Sopenharmony_ci struct phy_device *phydev, int speed, 302862306a36Sopenharmony_ci int duplex, bool tx_pause, bool rx_pause) 302962306a36Sopenharmony_ci{ 303062306a36Sopenharmony_ci struct ksz_device *dev = ds->priv; 303162306a36Sopenharmony_ci 303262306a36Sopenharmony_ci if (dev->dev_ops->phylink_mac_link_up) 303362306a36Sopenharmony_ci dev->dev_ops->phylink_mac_link_up(dev, port, mode, interface, 303462306a36Sopenharmony_ci phydev, speed, duplex, 303562306a36Sopenharmony_ci tx_pause, rx_pause); 303662306a36Sopenharmony_ci} 303762306a36Sopenharmony_ci 303862306a36Sopenharmony_cistatic int ksz_switch_detect(struct ksz_device *dev) 303962306a36Sopenharmony_ci{ 304062306a36Sopenharmony_ci u8 id1, id2, id4; 304162306a36Sopenharmony_ci u16 id16; 304262306a36Sopenharmony_ci u32 id32; 304362306a36Sopenharmony_ci int ret; 304462306a36Sopenharmony_ci 304562306a36Sopenharmony_ci /* read chip id */ 304662306a36Sopenharmony_ci ret = ksz_read16(dev, REG_CHIP_ID0, &id16); 304762306a36Sopenharmony_ci if (ret) 304862306a36Sopenharmony_ci return ret; 304962306a36Sopenharmony_ci 305062306a36Sopenharmony_ci id1 = FIELD_GET(SW_FAMILY_ID_M, id16); 305162306a36Sopenharmony_ci id2 = FIELD_GET(SW_CHIP_ID_M, id16); 305262306a36Sopenharmony_ci 305362306a36Sopenharmony_ci switch (id1) { 305462306a36Sopenharmony_ci case KSZ87_FAMILY_ID: 305562306a36Sopenharmony_ci if (id2 == KSZ87_CHIP_ID_95) { 305662306a36Sopenharmony_ci u8 val; 305762306a36Sopenharmony_ci 305862306a36Sopenharmony_ci dev->chip_id = KSZ8795_CHIP_ID; 305962306a36Sopenharmony_ci 306062306a36Sopenharmony_ci ksz_read8(dev, KSZ8_PORT_STATUS_0, &val); 306162306a36Sopenharmony_ci if (val & KSZ8_PORT_FIBER_MODE) 306262306a36Sopenharmony_ci dev->chip_id = KSZ8765_CHIP_ID; 306362306a36Sopenharmony_ci } else if (id2 == KSZ87_CHIP_ID_94) { 306462306a36Sopenharmony_ci dev->chip_id = KSZ8794_CHIP_ID; 306562306a36Sopenharmony_ci } else { 306662306a36Sopenharmony_ci return -ENODEV; 306762306a36Sopenharmony_ci } 306862306a36Sopenharmony_ci break; 306962306a36Sopenharmony_ci case KSZ88_FAMILY_ID: 307062306a36Sopenharmony_ci if (id2 == KSZ88_CHIP_ID_63) 307162306a36Sopenharmony_ci dev->chip_id = KSZ8830_CHIP_ID; 307262306a36Sopenharmony_ci else 307362306a36Sopenharmony_ci return -ENODEV; 307462306a36Sopenharmony_ci break; 307562306a36Sopenharmony_ci default: 307662306a36Sopenharmony_ci ret = ksz_read32(dev, REG_CHIP_ID0, &id32); 307762306a36Sopenharmony_ci if (ret) 307862306a36Sopenharmony_ci return ret; 307962306a36Sopenharmony_ci 308062306a36Sopenharmony_ci dev->chip_rev = FIELD_GET(SW_REV_ID_M, id32); 308162306a36Sopenharmony_ci id32 &= ~0xFF; 308262306a36Sopenharmony_ci 308362306a36Sopenharmony_ci switch (id32) { 308462306a36Sopenharmony_ci case KSZ9477_CHIP_ID: 308562306a36Sopenharmony_ci case KSZ9896_CHIP_ID: 308662306a36Sopenharmony_ci case KSZ9897_CHIP_ID: 308762306a36Sopenharmony_ci case KSZ9567_CHIP_ID: 308862306a36Sopenharmony_ci case LAN9370_CHIP_ID: 308962306a36Sopenharmony_ci case LAN9371_CHIP_ID: 309062306a36Sopenharmony_ci case LAN9372_CHIP_ID: 309162306a36Sopenharmony_ci case LAN9373_CHIP_ID: 309262306a36Sopenharmony_ci case LAN9374_CHIP_ID: 309362306a36Sopenharmony_ci dev->chip_id = id32; 309462306a36Sopenharmony_ci break; 309562306a36Sopenharmony_ci case KSZ9893_CHIP_ID: 309662306a36Sopenharmony_ci ret = ksz_read8(dev, REG_CHIP_ID4, 309762306a36Sopenharmony_ci &id4); 309862306a36Sopenharmony_ci if (ret) 309962306a36Sopenharmony_ci return ret; 310062306a36Sopenharmony_ci 310162306a36Sopenharmony_ci if (id4 == SKU_ID_KSZ8563) 310262306a36Sopenharmony_ci dev->chip_id = KSZ8563_CHIP_ID; 310362306a36Sopenharmony_ci else if (id4 == SKU_ID_KSZ9563) 310462306a36Sopenharmony_ci dev->chip_id = KSZ9563_CHIP_ID; 310562306a36Sopenharmony_ci else 310662306a36Sopenharmony_ci dev->chip_id = KSZ9893_CHIP_ID; 310762306a36Sopenharmony_ci 310862306a36Sopenharmony_ci break; 310962306a36Sopenharmony_ci default: 311062306a36Sopenharmony_ci dev_err(dev->dev, 311162306a36Sopenharmony_ci "unsupported switch detected %x)\n", id32); 311262306a36Sopenharmony_ci return -ENODEV; 311362306a36Sopenharmony_ci } 311462306a36Sopenharmony_ci } 311562306a36Sopenharmony_ci return 0; 311662306a36Sopenharmony_ci} 311762306a36Sopenharmony_ci 311862306a36Sopenharmony_ci/* Bandwidth is calculated by idle slope/transmission speed. Then the Bandwidth 311962306a36Sopenharmony_ci * is converted to Hex-decimal using the successive multiplication method. On 312062306a36Sopenharmony_ci * every step, integer part is taken and decimal part is carry forwarded. 312162306a36Sopenharmony_ci */ 312262306a36Sopenharmony_cistatic int cinc_cal(s32 idle_slope, s32 send_slope, u32 *bw) 312362306a36Sopenharmony_ci{ 312462306a36Sopenharmony_ci u32 cinc = 0; 312562306a36Sopenharmony_ci u32 txrate; 312662306a36Sopenharmony_ci u32 rate; 312762306a36Sopenharmony_ci u8 temp; 312862306a36Sopenharmony_ci u8 i; 312962306a36Sopenharmony_ci 313062306a36Sopenharmony_ci txrate = idle_slope - send_slope; 313162306a36Sopenharmony_ci 313262306a36Sopenharmony_ci if (!txrate) 313362306a36Sopenharmony_ci return -EINVAL; 313462306a36Sopenharmony_ci 313562306a36Sopenharmony_ci rate = idle_slope; 313662306a36Sopenharmony_ci 313762306a36Sopenharmony_ci /* 24 bit register */ 313862306a36Sopenharmony_ci for (i = 0; i < 6; i++) { 313962306a36Sopenharmony_ci rate = rate * 16; 314062306a36Sopenharmony_ci 314162306a36Sopenharmony_ci temp = rate / txrate; 314262306a36Sopenharmony_ci 314362306a36Sopenharmony_ci rate %= txrate; 314462306a36Sopenharmony_ci 314562306a36Sopenharmony_ci cinc = ((cinc << 4) | temp); 314662306a36Sopenharmony_ci } 314762306a36Sopenharmony_ci 314862306a36Sopenharmony_ci *bw = cinc; 314962306a36Sopenharmony_ci 315062306a36Sopenharmony_ci return 0; 315162306a36Sopenharmony_ci} 315262306a36Sopenharmony_ci 315362306a36Sopenharmony_cistatic int ksz_setup_tc_mode(struct ksz_device *dev, int port, u8 scheduler, 315462306a36Sopenharmony_ci u8 shaper) 315562306a36Sopenharmony_ci{ 315662306a36Sopenharmony_ci return ksz_pwrite8(dev, port, REG_PORT_MTI_QUEUE_CTRL_0, 315762306a36Sopenharmony_ci FIELD_PREP(MTI_SCHEDULE_MODE_M, scheduler) | 315862306a36Sopenharmony_ci FIELD_PREP(MTI_SHAPING_M, shaper)); 315962306a36Sopenharmony_ci} 316062306a36Sopenharmony_ci 316162306a36Sopenharmony_cistatic int ksz_setup_tc_cbs(struct dsa_switch *ds, int port, 316262306a36Sopenharmony_ci struct tc_cbs_qopt_offload *qopt) 316362306a36Sopenharmony_ci{ 316462306a36Sopenharmony_ci struct ksz_device *dev = ds->priv; 316562306a36Sopenharmony_ci int ret; 316662306a36Sopenharmony_ci u32 bw; 316762306a36Sopenharmony_ci 316862306a36Sopenharmony_ci if (!dev->info->tc_cbs_supported) 316962306a36Sopenharmony_ci return -EOPNOTSUPP; 317062306a36Sopenharmony_ci 317162306a36Sopenharmony_ci if (qopt->queue > dev->info->num_tx_queues) 317262306a36Sopenharmony_ci return -EINVAL; 317362306a36Sopenharmony_ci 317462306a36Sopenharmony_ci /* Queue Selection */ 317562306a36Sopenharmony_ci ret = ksz_pwrite32(dev, port, REG_PORT_MTI_QUEUE_INDEX__4, qopt->queue); 317662306a36Sopenharmony_ci if (ret) 317762306a36Sopenharmony_ci return ret; 317862306a36Sopenharmony_ci 317962306a36Sopenharmony_ci if (!qopt->enable) 318062306a36Sopenharmony_ci return ksz_setup_tc_mode(dev, port, MTI_SCHEDULE_WRR, 318162306a36Sopenharmony_ci MTI_SHAPING_OFF); 318262306a36Sopenharmony_ci 318362306a36Sopenharmony_ci /* High Credit */ 318462306a36Sopenharmony_ci ret = ksz_pwrite16(dev, port, REG_PORT_MTI_HI_WATER_MARK, 318562306a36Sopenharmony_ci qopt->hicredit); 318662306a36Sopenharmony_ci if (ret) 318762306a36Sopenharmony_ci return ret; 318862306a36Sopenharmony_ci 318962306a36Sopenharmony_ci /* Low Credit */ 319062306a36Sopenharmony_ci ret = ksz_pwrite16(dev, port, REG_PORT_MTI_LO_WATER_MARK, 319162306a36Sopenharmony_ci qopt->locredit); 319262306a36Sopenharmony_ci if (ret) 319362306a36Sopenharmony_ci return ret; 319462306a36Sopenharmony_ci 319562306a36Sopenharmony_ci /* Credit Increment Register */ 319662306a36Sopenharmony_ci ret = cinc_cal(qopt->idleslope, qopt->sendslope, &bw); 319762306a36Sopenharmony_ci if (ret) 319862306a36Sopenharmony_ci return ret; 319962306a36Sopenharmony_ci 320062306a36Sopenharmony_ci if (dev->dev_ops->tc_cbs_set_cinc) { 320162306a36Sopenharmony_ci ret = dev->dev_ops->tc_cbs_set_cinc(dev, port, bw); 320262306a36Sopenharmony_ci if (ret) 320362306a36Sopenharmony_ci return ret; 320462306a36Sopenharmony_ci } 320562306a36Sopenharmony_ci 320662306a36Sopenharmony_ci return ksz_setup_tc_mode(dev, port, MTI_SCHEDULE_STRICT_PRIO, 320762306a36Sopenharmony_ci MTI_SHAPING_SRP); 320862306a36Sopenharmony_ci} 320962306a36Sopenharmony_ci 321062306a36Sopenharmony_cistatic int ksz_disable_egress_rate_limit(struct ksz_device *dev, int port) 321162306a36Sopenharmony_ci{ 321262306a36Sopenharmony_ci int queue, ret; 321362306a36Sopenharmony_ci 321462306a36Sopenharmony_ci /* Configuration will not take effect until the last Port Queue X 321562306a36Sopenharmony_ci * Egress Limit Control Register is written. 321662306a36Sopenharmony_ci */ 321762306a36Sopenharmony_ci for (queue = 0; queue < dev->info->num_tx_queues; queue++) { 321862306a36Sopenharmony_ci ret = ksz_pwrite8(dev, port, KSZ9477_REG_PORT_OUT_RATE_0 + queue, 321962306a36Sopenharmony_ci KSZ9477_OUT_RATE_NO_LIMIT); 322062306a36Sopenharmony_ci if (ret) 322162306a36Sopenharmony_ci return ret; 322262306a36Sopenharmony_ci } 322362306a36Sopenharmony_ci 322462306a36Sopenharmony_ci return 0; 322562306a36Sopenharmony_ci} 322662306a36Sopenharmony_ci 322762306a36Sopenharmony_cistatic int ksz_ets_band_to_queue(struct tc_ets_qopt_offload_replace_params *p, 322862306a36Sopenharmony_ci int band) 322962306a36Sopenharmony_ci{ 323062306a36Sopenharmony_ci /* Compared to queues, bands prioritize packets differently. In strict 323162306a36Sopenharmony_ci * priority mode, the lowest priority is assigned to Queue 0 while the 323262306a36Sopenharmony_ci * highest priority is given to Band 0. 323362306a36Sopenharmony_ci */ 323462306a36Sopenharmony_ci return p->bands - 1 - band; 323562306a36Sopenharmony_ci} 323662306a36Sopenharmony_ci 323762306a36Sopenharmony_cistatic int ksz_queue_set_strict(struct ksz_device *dev, int port, int queue) 323862306a36Sopenharmony_ci{ 323962306a36Sopenharmony_ci int ret; 324062306a36Sopenharmony_ci 324162306a36Sopenharmony_ci ret = ksz_pwrite32(dev, port, REG_PORT_MTI_QUEUE_INDEX__4, queue); 324262306a36Sopenharmony_ci if (ret) 324362306a36Sopenharmony_ci return ret; 324462306a36Sopenharmony_ci 324562306a36Sopenharmony_ci return ksz_setup_tc_mode(dev, port, MTI_SCHEDULE_STRICT_PRIO, 324662306a36Sopenharmony_ci MTI_SHAPING_OFF); 324762306a36Sopenharmony_ci} 324862306a36Sopenharmony_ci 324962306a36Sopenharmony_cistatic int ksz_queue_set_wrr(struct ksz_device *dev, int port, int queue, 325062306a36Sopenharmony_ci int weight) 325162306a36Sopenharmony_ci{ 325262306a36Sopenharmony_ci int ret; 325362306a36Sopenharmony_ci 325462306a36Sopenharmony_ci ret = ksz_pwrite32(dev, port, REG_PORT_MTI_QUEUE_INDEX__4, queue); 325562306a36Sopenharmony_ci if (ret) 325662306a36Sopenharmony_ci return ret; 325762306a36Sopenharmony_ci 325862306a36Sopenharmony_ci ret = ksz_setup_tc_mode(dev, port, MTI_SCHEDULE_WRR, 325962306a36Sopenharmony_ci MTI_SHAPING_OFF); 326062306a36Sopenharmony_ci if (ret) 326162306a36Sopenharmony_ci return ret; 326262306a36Sopenharmony_ci 326362306a36Sopenharmony_ci return ksz_pwrite8(dev, port, KSZ9477_PORT_MTI_QUEUE_CTRL_1, weight); 326462306a36Sopenharmony_ci} 326562306a36Sopenharmony_ci 326662306a36Sopenharmony_cistatic int ksz_tc_ets_add(struct ksz_device *dev, int port, 326762306a36Sopenharmony_ci struct tc_ets_qopt_offload_replace_params *p) 326862306a36Sopenharmony_ci{ 326962306a36Sopenharmony_ci int ret, band, tc_prio; 327062306a36Sopenharmony_ci u32 queue_map = 0; 327162306a36Sopenharmony_ci 327262306a36Sopenharmony_ci /* In order to ensure proper prioritization, it is necessary to set the 327362306a36Sopenharmony_ci * rate limit for the related queue to zero. Otherwise strict priority 327462306a36Sopenharmony_ci * or WRR mode will not work. This is a hardware limitation. 327562306a36Sopenharmony_ci */ 327662306a36Sopenharmony_ci ret = ksz_disable_egress_rate_limit(dev, port); 327762306a36Sopenharmony_ci if (ret) 327862306a36Sopenharmony_ci return ret; 327962306a36Sopenharmony_ci 328062306a36Sopenharmony_ci /* Configure queue scheduling mode for all bands. Currently only strict 328162306a36Sopenharmony_ci * prio mode is supported. 328262306a36Sopenharmony_ci */ 328362306a36Sopenharmony_ci for (band = 0; band < p->bands; band++) { 328462306a36Sopenharmony_ci int queue = ksz_ets_band_to_queue(p, band); 328562306a36Sopenharmony_ci 328662306a36Sopenharmony_ci ret = ksz_queue_set_strict(dev, port, queue); 328762306a36Sopenharmony_ci if (ret) 328862306a36Sopenharmony_ci return ret; 328962306a36Sopenharmony_ci } 329062306a36Sopenharmony_ci 329162306a36Sopenharmony_ci /* Configure the mapping between traffic classes and queues. Note: 329262306a36Sopenharmony_ci * priomap variable support 16 traffic classes, but the chip can handle 329362306a36Sopenharmony_ci * only 8 classes. 329462306a36Sopenharmony_ci */ 329562306a36Sopenharmony_ci for (tc_prio = 0; tc_prio < ARRAY_SIZE(p->priomap); tc_prio++) { 329662306a36Sopenharmony_ci int queue; 329762306a36Sopenharmony_ci 329862306a36Sopenharmony_ci if (tc_prio > KSZ9477_MAX_TC_PRIO) 329962306a36Sopenharmony_ci break; 330062306a36Sopenharmony_ci 330162306a36Sopenharmony_ci queue = ksz_ets_band_to_queue(p, p->priomap[tc_prio]); 330262306a36Sopenharmony_ci queue_map |= queue << (tc_prio * KSZ9477_PORT_TC_MAP_S); 330362306a36Sopenharmony_ci } 330462306a36Sopenharmony_ci 330562306a36Sopenharmony_ci return ksz_pwrite32(dev, port, KSZ9477_PORT_MRI_TC_MAP__4, queue_map); 330662306a36Sopenharmony_ci} 330762306a36Sopenharmony_ci 330862306a36Sopenharmony_cistatic int ksz_tc_ets_del(struct ksz_device *dev, int port) 330962306a36Sopenharmony_ci{ 331062306a36Sopenharmony_ci int ret, queue, tc_prio, s; 331162306a36Sopenharmony_ci u32 queue_map = 0; 331262306a36Sopenharmony_ci 331362306a36Sopenharmony_ci /* To restore the default chip configuration, set all queues to use the 331462306a36Sopenharmony_ci * WRR scheduler with a weight of 1. 331562306a36Sopenharmony_ci */ 331662306a36Sopenharmony_ci for (queue = 0; queue < dev->info->num_tx_queues; queue++) { 331762306a36Sopenharmony_ci ret = ksz_queue_set_wrr(dev, port, queue, 331862306a36Sopenharmony_ci KSZ9477_DEFAULT_WRR_WEIGHT); 331962306a36Sopenharmony_ci if (ret) 332062306a36Sopenharmony_ci return ret; 332162306a36Sopenharmony_ci } 332262306a36Sopenharmony_ci 332362306a36Sopenharmony_ci switch (dev->info->num_tx_queues) { 332462306a36Sopenharmony_ci case 2: 332562306a36Sopenharmony_ci s = 2; 332662306a36Sopenharmony_ci break; 332762306a36Sopenharmony_ci case 4: 332862306a36Sopenharmony_ci s = 1; 332962306a36Sopenharmony_ci break; 333062306a36Sopenharmony_ci case 8: 333162306a36Sopenharmony_ci s = 0; 333262306a36Sopenharmony_ci break; 333362306a36Sopenharmony_ci default: 333462306a36Sopenharmony_ci return -EINVAL; 333562306a36Sopenharmony_ci } 333662306a36Sopenharmony_ci 333762306a36Sopenharmony_ci /* Revert the queue mapping for TC-priority to its default setting on 333862306a36Sopenharmony_ci * the chip. 333962306a36Sopenharmony_ci */ 334062306a36Sopenharmony_ci for (tc_prio = 0; tc_prio <= KSZ9477_MAX_TC_PRIO; tc_prio++) { 334162306a36Sopenharmony_ci int queue; 334262306a36Sopenharmony_ci 334362306a36Sopenharmony_ci queue = tc_prio >> s; 334462306a36Sopenharmony_ci queue_map |= queue << (tc_prio * KSZ9477_PORT_TC_MAP_S); 334562306a36Sopenharmony_ci } 334662306a36Sopenharmony_ci 334762306a36Sopenharmony_ci return ksz_pwrite32(dev, port, KSZ9477_PORT_MRI_TC_MAP__4, queue_map); 334862306a36Sopenharmony_ci} 334962306a36Sopenharmony_ci 335062306a36Sopenharmony_cistatic int ksz_tc_ets_validate(struct ksz_device *dev, int port, 335162306a36Sopenharmony_ci struct tc_ets_qopt_offload_replace_params *p) 335262306a36Sopenharmony_ci{ 335362306a36Sopenharmony_ci int band; 335462306a36Sopenharmony_ci 335562306a36Sopenharmony_ci /* Since it is not feasible to share one port among multiple qdisc, 335662306a36Sopenharmony_ci * the user must configure all available queues appropriately. 335762306a36Sopenharmony_ci */ 335862306a36Sopenharmony_ci if (p->bands != dev->info->num_tx_queues) { 335962306a36Sopenharmony_ci dev_err(dev->dev, "Not supported amount of bands. It should be %d\n", 336062306a36Sopenharmony_ci dev->info->num_tx_queues); 336162306a36Sopenharmony_ci return -EOPNOTSUPP; 336262306a36Sopenharmony_ci } 336362306a36Sopenharmony_ci 336462306a36Sopenharmony_ci for (band = 0; band < p->bands; ++band) { 336562306a36Sopenharmony_ci /* The KSZ switches utilize a weighted round robin configuration 336662306a36Sopenharmony_ci * where a certain number of packets can be transmitted from a 336762306a36Sopenharmony_ci * queue before the next queue is serviced. For more information 336862306a36Sopenharmony_ci * on this, refer to section 5.2.8.4 of the KSZ8565R 336962306a36Sopenharmony_ci * documentation on the Port Transmit Queue Control 1 Register. 337062306a36Sopenharmony_ci * However, the current ETS Qdisc implementation (as of February 337162306a36Sopenharmony_ci * 2023) assigns a weight to each queue based on the number of 337262306a36Sopenharmony_ci * bytes or extrapolated bandwidth in percentages. Since this 337362306a36Sopenharmony_ci * differs from the KSZ switches' method and we don't want to 337462306a36Sopenharmony_ci * fake support by converting bytes to packets, it is better to 337562306a36Sopenharmony_ci * return an error instead. 337662306a36Sopenharmony_ci */ 337762306a36Sopenharmony_ci if (p->quanta[band]) { 337862306a36Sopenharmony_ci dev_err(dev->dev, "Quanta/weights configuration is not supported.\n"); 337962306a36Sopenharmony_ci return -EOPNOTSUPP; 338062306a36Sopenharmony_ci } 338162306a36Sopenharmony_ci } 338262306a36Sopenharmony_ci 338362306a36Sopenharmony_ci return 0; 338462306a36Sopenharmony_ci} 338562306a36Sopenharmony_ci 338662306a36Sopenharmony_cistatic int ksz_tc_setup_qdisc_ets(struct dsa_switch *ds, int port, 338762306a36Sopenharmony_ci struct tc_ets_qopt_offload *qopt) 338862306a36Sopenharmony_ci{ 338962306a36Sopenharmony_ci struct ksz_device *dev = ds->priv; 339062306a36Sopenharmony_ci int ret; 339162306a36Sopenharmony_ci 339262306a36Sopenharmony_ci if (!dev->info->tc_ets_supported) 339362306a36Sopenharmony_ci return -EOPNOTSUPP; 339462306a36Sopenharmony_ci 339562306a36Sopenharmony_ci if (qopt->parent != TC_H_ROOT) { 339662306a36Sopenharmony_ci dev_err(dev->dev, "Parent should be \"root\"\n"); 339762306a36Sopenharmony_ci return -EOPNOTSUPP; 339862306a36Sopenharmony_ci } 339962306a36Sopenharmony_ci 340062306a36Sopenharmony_ci switch (qopt->command) { 340162306a36Sopenharmony_ci case TC_ETS_REPLACE: 340262306a36Sopenharmony_ci ret = ksz_tc_ets_validate(dev, port, &qopt->replace_params); 340362306a36Sopenharmony_ci if (ret) 340462306a36Sopenharmony_ci return ret; 340562306a36Sopenharmony_ci 340662306a36Sopenharmony_ci return ksz_tc_ets_add(dev, port, &qopt->replace_params); 340762306a36Sopenharmony_ci case TC_ETS_DESTROY: 340862306a36Sopenharmony_ci return ksz_tc_ets_del(dev, port); 340962306a36Sopenharmony_ci case TC_ETS_STATS: 341062306a36Sopenharmony_ci case TC_ETS_GRAFT: 341162306a36Sopenharmony_ci return -EOPNOTSUPP; 341262306a36Sopenharmony_ci } 341362306a36Sopenharmony_ci 341462306a36Sopenharmony_ci return -EOPNOTSUPP; 341562306a36Sopenharmony_ci} 341662306a36Sopenharmony_ci 341762306a36Sopenharmony_cistatic int ksz_setup_tc(struct dsa_switch *ds, int port, 341862306a36Sopenharmony_ci enum tc_setup_type type, void *type_data) 341962306a36Sopenharmony_ci{ 342062306a36Sopenharmony_ci switch (type) { 342162306a36Sopenharmony_ci case TC_SETUP_QDISC_CBS: 342262306a36Sopenharmony_ci return ksz_setup_tc_cbs(ds, port, type_data); 342362306a36Sopenharmony_ci case TC_SETUP_QDISC_ETS: 342462306a36Sopenharmony_ci return ksz_tc_setup_qdisc_ets(ds, port, type_data); 342562306a36Sopenharmony_ci default: 342662306a36Sopenharmony_ci return -EOPNOTSUPP; 342762306a36Sopenharmony_ci } 342862306a36Sopenharmony_ci} 342962306a36Sopenharmony_ci 343062306a36Sopenharmony_cistatic const struct dsa_switch_ops ksz_switch_ops = { 343162306a36Sopenharmony_ci .get_tag_protocol = ksz_get_tag_protocol, 343262306a36Sopenharmony_ci .connect_tag_protocol = ksz_connect_tag_protocol, 343362306a36Sopenharmony_ci .get_phy_flags = ksz_get_phy_flags, 343462306a36Sopenharmony_ci .setup = ksz_setup, 343562306a36Sopenharmony_ci .teardown = ksz_teardown, 343662306a36Sopenharmony_ci .phy_read = ksz_phy_read16, 343762306a36Sopenharmony_ci .phy_write = ksz_phy_write16, 343862306a36Sopenharmony_ci .phylink_get_caps = ksz_phylink_get_caps, 343962306a36Sopenharmony_ci .phylink_mac_config = ksz_phylink_mac_config, 344062306a36Sopenharmony_ci .phylink_mac_link_up = ksz_phylink_mac_link_up, 344162306a36Sopenharmony_ci .phylink_mac_link_down = ksz_mac_link_down, 344262306a36Sopenharmony_ci .port_enable = ksz_enable_port, 344362306a36Sopenharmony_ci .set_ageing_time = ksz_set_ageing_time, 344462306a36Sopenharmony_ci .get_strings = ksz_get_strings, 344562306a36Sopenharmony_ci .get_ethtool_stats = ksz_get_ethtool_stats, 344662306a36Sopenharmony_ci .get_sset_count = ksz_sset_count, 344762306a36Sopenharmony_ci .port_bridge_join = ksz_port_bridge_join, 344862306a36Sopenharmony_ci .port_bridge_leave = ksz_port_bridge_leave, 344962306a36Sopenharmony_ci .port_stp_state_set = ksz_port_stp_state_set, 345062306a36Sopenharmony_ci .port_pre_bridge_flags = ksz_port_pre_bridge_flags, 345162306a36Sopenharmony_ci .port_bridge_flags = ksz_port_bridge_flags, 345262306a36Sopenharmony_ci .port_fast_age = ksz_port_fast_age, 345362306a36Sopenharmony_ci .port_vlan_filtering = ksz_port_vlan_filtering, 345462306a36Sopenharmony_ci .port_vlan_add = ksz_port_vlan_add, 345562306a36Sopenharmony_ci .port_vlan_del = ksz_port_vlan_del, 345662306a36Sopenharmony_ci .port_fdb_dump = ksz_port_fdb_dump, 345762306a36Sopenharmony_ci .port_fdb_add = ksz_port_fdb_add, 345862306a36Sopenharmony_ci .port_fdb_del = ksz_port_fdb_del, 345962306a36Sopenharmony_ci .port_mdb_add = ksz_port_mdb_add, 346062306a36Sopenharmony_ci .port_mdb_del = ksz_port_mdb_del, 346162306a36Sopenharmony_ci .port_mirror_add = ksz_port_mirror_add, 346262306a36Sopenharmony_ci .port_mirror_del = ksz_port_mirror_del, 346362306a36Sopenharmony_ci .get_stats64 = ksz_get_stats64, 346462306a36Sopenharmony_ci .get_pause_stats = ksz_get_pause_stats, 346562306a36Sopenharmony_ci .port_change_mtu = ksz_change_mtu, 346662306a36Sopenharmony_ci .port_max_mtu = ksz_max_mtu, 346762306a36Sopenharmony_ci .get_ts_info = ksz_get_ts_info, 346862306a36Sopenharmony_ci .port_hwtstamp_get = ksz_hwtstamp_get, 346962306a36Sopenharmony_ci .port_hwtstamp_set = ksz_hwtstamp_set, 347062306a36Sopenharmony_ci .port_txtstamp = ksz_port_txtstamp, 347162306a36Sopenharmony_ci .port_rxtstamp = ksz_port_rxtstamp, 347262306a36Sopenharmony_ci .port_setup_tc = ksz_setup_tc, 347362306a36Sopenharmony_ci .get_mac_eee = ksz_get_mac_eee, 347462306a36Sopenharmony_ci .set_mac_eee = ksz_set_mac_eee, 347562306a36Sopenharmony_ci}; 347662306a36Sopenharmony_ci 347762306a36Sopenharmony_cistruct ksz_device *ksz_switch_alloc(struct device *base, void *priv) 347862306a36Sopenharmony_ci{ 347962306a36Sopenharmony_ci struct dsa_switch *ds; 348062306a36Sopenharmony_ci struct ksz_device *swdev; 348162306a36Sopenharmony_ci 348262306a36Sopenharmony_ci ds = devm_kzalloc(base, sizeof(*ds), GFP_KERNEL); 348362306a36Sopenharmony_ci if (!ds) 348462306a36Sopenharmony_ci return NULL; 348562306a36Sopenharmony_ci 348662306a36Sopenharmony_ci ds->dev = base; 348762306a36Sopenharmony_ci ds->num_ports = DSA_MAX_PORTS; 348862306a36Sopenharmony_ci ds->ops = &ksz_switch_ops; 348962306a36Sopenharmony_ci 349062306a36Sopenharmony_ci swdev = devm_kzalloc(base, sizeof(*swdev), GFP_KERNEL); 349162306a36Sopenharmony_ci if (!swdev) 349262306a36Sopenharmony_ci return NULL; 349362306a36Sopenharmony_ci 349462306a36Sopenharmony_ci ds->priv = swdev; 349562306a36Sopenharmony_ci swdev->dev = base; 349662306a36Sopenharmony_ci 349762306a36Sopenharmony_ci swdev->ds = ds; 349862306a36Sopenharmony_ci swdev->priv = priv; 349962306a36Sopenharmony_ci 350062306a36Sopenharmony_ci return swdev; 350162306a36Sopenharmony_ci} 350262306a36Sopenharmony_ciEXPORT_SYMBOL(ksz_switch_alloc); 350362306a36Sopenharmony_ci 350462306a36Sopenharmony_cistatic void ksz_parse_rgmii_delay(struct ksz_device *dev, int port_num, 350562306a36Sopenharmony_ci struct device_node *port_dn) 350662306a36Sopenharmony_ci{ 350762306a36Sopenharmony_ci phy_interface_t phy_mode = dev->ports[port_num].interface; 350862306a36Sopenharmony_ci int rx_delay = -1, tx_delay = -1; 350962306a36Sopenharmony_ci 351062306a36Sopenharmony_ci if (!phy_interface_mode_is_rgmii(phy_mode)) 351162306a36Sopenharmony_ci return; 351262306a36Sopenharmony_ci 351362306a36Sopenharmony_ci of_property_read_u32(port_dn, "rx-internal-delay-ps", &rx_delay); 351462306a36Sopenharmony_ci of_property_read_u32(port_dn, "tx-internal-delay-ps", &tx_delay); 351562306a36Sopenharmony_ci 351662306a36Sopenharmony_ci if (rx_delay == -1 && tx_delay == -1) { 351762306a36Sopenharmony_ci dev_warn(dev->dev, 351862306a36Sopenharmony_ci "Port %d interpreting RGMII delay settings based on \"phy-mode\" property, " 351962306a36Sopenharmony_ci "please update device tree to specify \"rx-internal-delay-ps\" and " 352062306a36Sopenharmony_ci "\"tx-internal-delay-ps\"", 352162306a36Sopenharmony_ci port_num); 352262306a36Sopenharmony_ci 352362306a36Sopenharmony_ci if (phy_mode == PHY_INTERFACE_MODE_RGMII_RXID || 352462306a36Sopenharmony_ci phy_mode == PHY_INTERFACE_MODE_RGMII_ID) 352562306a36Sopenharmony_ci rx_delay = 2000; 352662306a36Sopenharmony_ci 352762306a36Sopenharmony_ci if (phy_mode == PHY_INTERFACE_MODE_RGMII_TXID || 352862306a36Sopenharmony_ci phy_mode == PHY_INTERFACE_MODE_RGMII_ID) 352962306a36Sopenharmony_ci tx_delay = 2000; 353062306a36Sopenharmony_ci } 353162306a36Sopenharmony_ci 353262306a36Sopenharmony_ci if (rx_delay < 0) 353362306a36Sopenharmony_ci rx_delay = 0; 353462306a36Sopenharmony_ci if (tx_delay < 0) 353562306a36Sopenharmony_ci tx_delay = 0; 353662306a36Sopenharmony_ci 353762306a36Sopenharmony_ci dev->ports[port_num].rgmii_rx_val = rx_delay; 353862306a36Sopenharmony_ci dev->ports[port_num].rgmii_tx_val = tx_delay; 353962306a36Sopenharmony_ci} 354062306a36Sopenharmony_ci 354162306a36Sopenharmony_ciint ksz_switch_register(struct ksz_device *dev) 354262306a36Sopenharmony_ci{ 354362306a36Sopenharmony_ci const struct ksz_chip_data *info; 354462306a36Sopenharmony_ci struct device_node *port, *ports; 354562306a36Sopenharmony_ci phy_interface_t interface; 354662306a36Sopenharmony_ci unsigned int port_num; 354762306a36Sopenharmony_ci int ret; 354862306a36Sopenharmony_ci int i; 354962306a36Sopenharmony_ci 355062306a36Sopenharmony_ci if (dev->pdata) 355162306a36Sopenharmony_ci dev->chip_id = dev->pdata->chip_id; 355262306a36Sopenharmony_ci 355362306a36Sopenharmony_ci dev->reset_gpio = devm_gpiod_get_optional(dev->dev, "reset", 355462306a36Sopenharmony_ci GPIOD_OUT_LOW); 355562306a36Sopenharmony_ci if (IS_ERR(dev->reset_gpio)) 355662306a36Sopenharmony_ci return PTR_ERR(dev->reset_gpio); 355762306a36Sopenharmony_ci 355862306a36Sopenharmony_ci if (dev->reset_gpio) { 355962306a36Sopenharmony_ci gpiod_set_value_cansleep(dev->reset_gpio, 1); 356062306a36Sopenharmony_ci usleep_range(10000, 12000); 356162306a36Sopenharmony_ci gpiod_set_value_cansleep(dev->reset_gpio, 0); 356262306a36Sopenharmony_ci msleep(100); 356362306a36Sopenharmony_ci } 356462306a36Sopenharmony_ci 356562306a36Sopenharmony_ci mutex_init(&dev->dev_mutex); 356662306a36Sopenharmony_ci mutex_init(&dev->regmap_mutex); 356762306a36Sopenharmony_ci mutex_init(&dev->alu_mutex); 356862306a36Sopenharmony_ci mutex_init(&dev->vlan_mutex); 356962306a36Sopenharmony_ci 357062306a36Sopenharmony_ci ret = ksz_switch_detect(dev); 357162306a36Sopenharmony_ci if (ret) 357262306a36Sopenharmony_ci return ret; 357362306a36Sopenharmony_ci 357462306a36Sopenharmony_ci info = ksz_lookup_info(dev->chip_id); 357562306a36Sopenharmony_ci if (!info) 357662306a36Sopenharmony_ci return -ENODEV; 357762306a36Sopenharmony_ci 357862306a36Sopenharmony_ci /* Update the compatible info with the probed one */ 357962306a36Sopenharmony_ci dev->info = info; 358062306a36Sopenharmony_ci 358162306a36Sopenharmony_ci dev_info(dev->dev, "found switch: %s, rev %i\n", 358262306a36Sopenharmony_ci dev->info->dev_name, dev->chip_rev); 358362306a36Sopenharmony_ci 358462306a36Sopenharmony_ci ret = ksz_check_device_id(dev); 358562306a36Sopenharmony_ci if (ret) 358662306a36Sopenharmony_ci return ret; 358762306a36Sopenharmony_ci 358862306a36Sopenharmony_ci dev->dev_ops = dev->info->ops; 358962306a36Sopenharmony_ci 359062306a36Sopenharmony_ci ret = dev->dev_ops->init(dev); 359162306a36Sopenharmony_ci if (ret) 359262306a36Sopenharmony_ci return ret; 359362306a36Sopenharmony_ci 359462306a36Sopenharmony_ci dev->ports = devm_kzalloc(dev->dev, 359562306a36Sopenharmony_ci dev->info->port_cnt * sizeof(struct ksz_port), 359662306a36Sopenharmony_ci GFP_KERNEL); 359762306a36Sopenharmony_ci if (!dev->ports) 359862306a36Sopenharmony_ci return -ENOMEM; 359962306a36Sopenharmony_ci 360062306a36Sopenharmony_ci for (i = 0; i < dev->info->port_cnt; i++) { 360162306a36Sopenharmony_ci spin_lock_init(&dev->ports[i].mib.stats64_lock); 360262306a36Sopenharmony_ci mutex_init(&dev->ports[i].mib.cnt_mutex); 360362306a36Sopenharmony_ci dev->ports[i].mib.counters = 360462306a36Sopenharmony_ci devm_kzalloc(dev->dev, 360562306a36Sopenharmony_ci sizeof(u64) * (dev->info->mib_cnt + 1), 360662306a36Sopenharmony_ci GFP_KERNEL); 360762306a36Sopenharmony_ci if (!dev->ports[i].mib.counters) 360862306a36Sopenharmony_ci return -ENOMEM; 360962306a36Sopenharmony_ci 361062306a36Sopenharmony_ci dev->ports[i].ksz_dev = dev; 361162306a36Sopenharmony_ci dev->ports[i].num = i; 361262306a36Sopenharmony_ci } 361362306a36Sopenharmony_ci 361462306a36Sopenharmony_ci /* set the real number of ports */ 361562306a36Sopenharmony_ci dev->ds->num_ports = dev->info->port_cnt; 361662306a36Sopenharmony_ci 361762306a36Sopenharmony_ci /* Host port interface will be self detected, or specifically set in 361862306a36Sopenharmony_ci * device tree. 361962306a36Sopenharmony_ci */ 362062306a36Sopenharmony_ci for (port_num = 0; port_num < dev->info->port_cnt; ++port_num) 362162306a36Sopenharmony_ci dev->ports[port_num].interface = PHY_INTERFACE_MODE_NA; 362262306a36Sopenharmony_ci if (dev->dev->of_node) { 362362306a36Sopenharmony_ci ret = of_get_phy_mode(dev->dev->of_node, &interface); 362462306a36Sopenharmony_ci if (ret == 0) 362562306a36Sopenharmony_ci dev->compat_interface = interface; 362662306a36Sopenharmony_ci ports = of_get_child_by_name(dev->dev->of_node, "ethernet-ports"); 362762306a36Sopenharmony_ci if (!ports) 362862306a36Sopenharmony_ci ports = of_get_child_by_name(dev->dev->of_node, "ports"); 362962306a36Sopenharmony_ci if (ports) { 363062306a36Sopenharmony_ci for_each_available_child_of_node(ports, port) { 363162306a36Sopenharmony_ci if (of_property_read_u32(port, "reg", 363262306a36Sopenharmony_ci &port_num)) 363362306a36Sopenharmony_ci continue; 363462306a36Sopenharmony_ci if (!(dev->port_mask & BIT(port_num))) { 363562306a36Sopenharmony_ci of_node_put(port); 363662306a36Sopenharmony_ci of_node_put(ports); 363762306a36Sopenharmony_ci return -EINVAL; 363862306a36Sopenharmony_ci } 363962306a36Sopenharmony_ci of_get_phy_mode(port, 364062306a36Sopenharmony_ci &dev->ports[port_num].interface); 364162306a36Sopenharmony_ci 364262306a36Sopenharmony_ci ksz_parse_rgmii_delay(dev, port_num, port); 364362306a36Sopenharmony_ci } 364462306a36Sopenharmony_ci of_node_put(ports); 364562306a36Sopenharmony_ci } 364662306a36Sopenharmony_ci dev->synclko_125 = of_property_read_bool(dev->dev->of_node, 364762306a36Sopenharmony_ci "microchip,synclko-125"); 364862306a36Sopenharmony_ci dev->synclko_disable = of_property_read_bool(dev->dev->of_node, 364962306a36Sopenharmony_ci "microchip,synclko-disable"); 365062306a36Sopenharmony_ci if (dev->synclko_125 && dev->synclko_disable) { 365162306a36Sopenharmony_ci dev_err(dev->dev, "inconsistent synclko settings\n"); 365262306a36Sopenharmony_ci return -EINVAL; 365362306a36Sopenharmony_ci } 365462306a36Sopenharmony_ci } 365562306a36Sopenharmony_ci 365662306a36Sopenharmony_ci ret = dsa_register_switch(dev->ds); 365762306a36Sopenharmony_ci if (ret) { 365862306a36Sopenharmony_ci dev->dev_ops->exit(dev); 365962306a36Sopenharmony_ci return ret; 366062306a36Sopenharmony_ci } 366162306a36Sopenharmony_ci 366262306a36Sopenharmony_ci /* Read MIB counters every 30 seconds to avoid overflow. */ 366362306a36Sopenharmony_ci dev->mib_read_interval = msecs_to_jiffies(5000); 366462306a36Sopenharmony_ci 366562306a36Sopenharmony_ci /* Start the MIB timer. */ 366662306a36Sopenharmony_ci schedule_delayed_work(&dev->mib_read, 0); 366762306a36Sopenharmony_ci 366862306a36Sopenharmony_ci return ret; 366962306a36Sopenharmony_ci} 367062306a36Sopenharmony_ciEXPORT_SYMBOL(ksz_switch_register); 367162306a36Sopenharmony_ci 367262306a36Sopenharmony_civoid ksz_switch_remove(struct ksz_device *dev) 367362306a36Sopenharmony_ci{ 367462306a36Sopenharmony_ci /* timer started */ 367562306a36Sopenharmony_ci if (dev->mib_read_interval) { 367662306a36Sopenharmony_ci dev->mib_read_interval = 0; 367762306a36Sopenharmony_ci cancel_delayed_work_sync(&dev->mib_read); 367862306a36Sopenharmony_ci } 367962306a36Sopenharmony_ci 368062306a36Sopenharmony_ci dev->dev_ops->exit(dev); 368162306a36Sopenharmony_ci dsa_unregister_switch(dev->ds); 368262306a36Sopenharmony_ci 368362306a36Sopenharmony_ci if (dev->reset_gpio) 368462306a36Sopenharmony_ci gpiod_set_value_cansleep(dev->reset_gpio, 1); 368562306a36Sopenharmony_ci 368662306a36Sopenharmony_ci} 368762306a36Sopenharmony_ciEXPORT_SYMBOL(ksz_switch_remove); 368862306a36Sopenharmony_ci 368962306a36Sopenharmony_ciMODULE_AUTHOR("Woojung Huh <Woojung.Huh@microchip.com>"); 369062306a36Sopenharmony_ciMODULE_DESCRIPTION("Microchip KSZ Series Switch DSA Driver"); 369162306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 3692